代码改变世界

位图 c语言算法

2013-04-22 23:09  keiigzy123  阅读(339)  评论(0)    收藏  举报
//<<<<<<<<<<<<<<<<<<<<<<<<author gaizengyuan <<<<<<<<<<<<<<<<<<<<<
//<<<<<<<<<<<<<<<<<<<<<<<< time 2013.04.22<<<<<<<<<<<<<<<<<<<
//<<<<<<<<<<<<<<<<<<<<<<没有完善,后续继续改进<<<<<<<<<<<<<<<<<<<
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define GET_gray(bmp,i,j) ( *( bmp.ptr + bmp.line_width * i + j ) )//找到i行j列的像素地址
#define SET_gray(bmp,i,j,v) ( *( bmp.ptr + bmp.line_width * i + j ) = v )
typedef unsigned char  BYTE;//定义BYTE类型,占1个字节
typedef unsigned short USHORT;//定义USHORT类型,占2个字节
typedef unsigned long  ULONG;//定义ULONG类型,占4个字节
//<<<<<<<<<<<<<<<<<<<<<<<<   图像数据的全局参数<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,//
ULONG off_bits , width , height , line_width ;
USHORT bit_count , pal_length ;
//<<<<<<<<<<<<<<<<<<<  滤波掩膜的设置量(全局参数)    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
int nSize=3;
int nW=nSize/2;
int nWSize=nSize*nSize;
int* OffSetX=(int*)malloc(nSize*sizeof(int));//X方向的偏移量
int* OffSetY=(int*)malloc(nSize*sizeof(int));//Y方向的偏移量
BYTE*MedianArray=(BYTE*)malloc(nWSize*sizeof(BYTE));//中间求中值的时候需要的数组
BYTE*dst=(BYTE*)malloc( line_width*height*sizeof(BYTE));//处理完后把数据放在dst中
//////////////////定义结构体////////////////////////////////
typedef struct tagCxBitmap //定义CxBitmap结构体
{
BYTE* ptr;  //指向位图的像素数据(0~255之间)
ULONG width;  //位图的宽度
ULONG height;  //位图的高度
USHORT  bit_count; //位图的位数
ULONG line_width; //位图每行像素所占的字节数
USHORT  pal_length; //位图调色板的长度
BYTE* palette;  //指向位图的调色板
}CxBitmap;

//>>>>>>>>>>>>>>>>>>>定义找出数组的中值函数>>>>>>>>>>>>>>>>>>>>>>>>>//
BYTE GetMedianNum(BYTE* bArray,int  ilen)
{
    //循环变量
    int i,j;
    BYTE bTemp;
    for(i=0;i<ilen-1;++i)
    {    for(j=0;j<ilen-i-1;++j)
        {
            if (bArray[j]>bArray[j+1])
            {
            bTemp=bArray[j];
            bArray[i]=bArray[i+1];
            bArray[i+1]=bTemp;

            }
        }

    }

    if((ilen&1)>0)
    {
        bTemp=bArray[(ilen/2+1)];

    }
    else
    {
    bTemp=(bArray[ilen/2]+bArray[ilen/2+1])/2;
    }
    return bTemp;
};

///////////////////////   main主函数  //////////////////////////////
int main()
{

    BYTE b = 0;
    CxBitmap bmp;
    FILE *fp = 0;
    
    ULONG dw = 0;
    USHORT  w = 0;
    char path[256];
    char outpath[256];
    printf("Input the bitmap path: ");
    scanf("%s",path);
    if((fp = fopen( path, "rb" )) == NULL)
    {
    printf("can not open the bitmap " );
    return 1;
    }
    else printf("read OK");
//////////////读入图像参数//////////////////////////////////////////////////////
    fseek( fp, 10, 0 );//set fp's 位置以0为基准偏移10
    fread( &off_bits, 4, 1, fp );//从fp中读1个4长度的值到&off_bits
    fseek( fp, 18, 0 );
    fread( &width, 4, 1, fp );//图像的宽度
    fread( &height, 4, 1, fp );//图像的高度
    fseek( fp, 28, 0 );
    fread( &bit_count, 2, 1, fp );//位图的位数


    //<<<<<<<<<<<<<<<<<<<<<<  读取调色板的信息<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//



    pal_length = off_bits - 54; //调色板的颜色个数,前五十四个字节为文件头结构体和图像信息结构体。
    if( bit_count == 8 )
            {
                bmp.palette = (BYTE*)malloc( pal_length * sizeof(BYTE) );//调色板内存
    
                if( !bmp.palette ) 
                    {
                        printf("调色板申请内存失败");
                        return 0;
                    }
            }
    else
            {
               bmp.palette = 0;//如果不是8位,就不用调色板
            }

    if( bmp.palette )
        {
            fseek( fp, 54, 0 );
            fread( bmp.palette, pal_length, 1, fp );//把调色板数据读取到申请的内存中
        }



    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    图像数据区的读取  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,//



    line_width = ( width * bit_count + 31 ) / 32 * 4;//位图每行像素所占的字节数=(位图的宽度*位图的位数+31)/32*4
    bmp.line_width = line_width;
    bmp.width = width;
    bmp.height = height;
    bmp.bit_count = bit_count;
    bmp.pal_length = pal_length;
    bmp.ptr = (BYTE*)malloc( line_width * height * sizeof(BYTE) );//指向位图的像素数据(0~255之间)
    /*把图像像素复制到B中*/
    

    if( !bmp.ptr )
    {
    printf("为图像数据区申请内存失败");
    bmp.width = 0;
    bmp.height = 0;
    bmp.bit_count = 0;
    return  0;
    }

    fseek( fp, off_bits, 0 );
    fread( bmp.ptr, line_width * height, 1, fp );
    fclose( fp );//参数读完,关闭文件
///////////////////////////////////////////////////////////////////////////////////////////
    printf("Bitmap Width: %ld\n",bmp.width);
    printf("Bitmap Height: %ld\n",bmp.height);
    printf("Bitmap BitCount: %d\n",bmp.bit_count);
    printf("loaded the bitmap successfully...\n");

//////////////////////////////////处理图像矩阵(中值滤波)//////////////////////////////////////////////////////
    //循环变量
    int k,i = 0, j = 0;
    int index;


    //<<<<<<<<<<,nSize*nSize模<<<<<<<<<<<<<<<<<<<<<<<<<
    
    for(i=0;i<nSize;i++)
    {
        for(j=0;j<nSize;j++)
        {
          OffSetY[i*nSize+j]=-nW+i;
          OffSetX[i*nSize+j]=-nW+j;
        
        }
    };

index=0;
for(i=0;i<height-1;i++)
{
    for(j=0;j<width-1;j++)
    {
        if(i<nW||j<nW||i>height-nW-1||j>width-nW-1)//图像边缘部分的处理
            {
               dst[index]= GET_gray(bmp,i,j);
            }
        
        else{   for(k=0;k<nWSize;k++)
                {
                      MedianArray[k]= GET_gray(bmp,(i+OffSetY[k]),(j+OffSetX[k]));
                }
                      dst[index]=GetMedianNum(MedianArray,nWSize);//图像中央部分的处理
         
                   index++;
          }
    }
    
};
 
    int index2=0;
    for( i = 0; i < bmp.height; i++ )
        {
        for( j = 0; j < bmp.width ; j ++ )
           {   
               index2=i*bmp.line_width+j;
               b=dst[index2];                   //处理的数据写会到源图像中
               SET_gray( bmp, i, j ,b);
            
            }
        }
//////////////////////////保存///////////////////////////////////////////////////////////
    printf("Input the bitmap path for save: ");
    scanf("%s",outpath);
    if( ( fp = fopen( outpath, "wb" ) ) == NULL )
        {
            printf("can not create the bitmap : %s\n", outpath );
            return 0;
        }
//<<<<<<<<<<<<<<<<<图像文件头的读入<<<<<<<<<<<<<<<<<<<<<<<<<<,
    w = 19778;//第一个标志位,也就是‘BM’
    fwrite( &w, 2, 1, fp );
    dw = 14;//   图像文件头的大小14字节
    fwrite( &dw, 4, 1, fp );
    w = 0;
    fwrite( &w, 2, 1, fp );//保留位
    fwrite( &w, 2, 1, fp );//保留位
    if( bmp.bit_count == 8 ) dw = 1078;//从文件数据开始到数据区的偏移量,包含三部分(文件头,信息头,调色板)
    else  dw = 54;//没有调色板的情况下,只有两个头结构体
    fwrite( &dw, 4, 1, fp );

    dw = 40;//信息头文件的大小
    fwrite( &dw, 4, 1, fp );
    dw = bmp.width;
    fwrite( &dw, 4, 1, fp );//写入宽度
    dw = bmp.height;
    fwrite( &dw, 4, 1, fp );//写入高度
    w = 0;
    fwrite( &w, 2, 1, fp );//位平面数
    w = bmp.bit_count;
    fwrite( &w, 2, 1, fp );//写入单位像素位数
    dw = 0;
    fwrite( &dw, 4, 1, fp );//写入压缩特性0表示无压缩
    dw = bmp.height * ( bmp.width * bmp.bit_count + 31 ) / 32 * 4;//求出像素区的大小
    fwrite( &dw, 4, 1, fp );//写入像素数据区区的大小的值
    dw = 0;
    fwrite( &dw, 4, 1, fp );//水平颜色分辨率,这里写默认值
    fwrite( &dw, 4, 1, fp );//垂直颜色分辨率,同上
    fwrite( &dw, 4, 1, fp );//使用所有的颜色索引表
    fwrite( &dw, 4, 1, fp );//所有的颜色都重要

    if( bmp.palette != 0 )
    {
       fwrite( bmp.palette, 1024, 1, fp );//这里是256*4,一共使用256个索引表,每个索引表占四个字节
    }

    dw = bmp.height * ( bmp.width * bmp.bit_count + 31 ) / 32 * 4;
    fwrite( bmp.ptr, dw, 1, fp );//写入图像部分

    fclose(fp);
    
/////////////////////////////////////////////////////////////////////////////////////

return 0;
}