c语言实现BMP图像转换为灰度图

当初是自己要装X,非要用c来写信息隐藏作业,装了X,就得付出实践。查了好久资料,到期末才把作业交了,这里总结一下。

这道题是将真彩图转换为灰度图

  • 关于BMP文件结构,这是困扰了我好久的问题,上网查了很久图片的知识才弄明白
  • BMP文件包括以下几部分(具体结构在程序中说明):
    • 位图文件头
    • 位图信息头
    • 调色板
    • 位图数据
  • 结构体内存对齐原则对于pragma pack(n)
    • 当成员大小小于n时,每个成员存储的起始位置要从该成员大小的整数倍开始,否则从n的整数倍开始
    • 成员是结构体时相对于起始偏移是以其内部最大成员为准
    • 当n大于内部最大成员时,结构体的总大小是其内部最大成员的整数倍反之为n的整数倍
    • 32位默认n为4,64位默认为8
  • 因此在定义头结构的时候要加上#pragma pack(1),设置以1字节为对齐方式,不然后面数据会错位
  1 /*
  2 真彩图转换成灰度图的改进版
  3 (不把真彩图的每个像素点放入二维矩阵,而是读一行写一行)
  4 blog:http://www.cnblogs.com/wd1001/
  5 2015年6月2日19:04:09
  6 */
  7 #include<stdio.h>
  8 #include<malloc.h>
  9 #include<stdlib.h>
 10 /*
 11 位图头结构
 12 */
 13 #pragma pack(1)
 14 typedef struct tagBITMAPFILEHEADER
 15 {
 16     unsigned char bfType[2];//文件格式
 17     unsigned long bfSize;//文件大小
 18     unsigned short bfReserved1;//保留
 19     unsigned short bfReserved2;
 20     unsigned long bfOffBits; //DIB数据在文件中的偏移量
 21 }fileHeader;
 22 #pragma pack()
 23 /*
 24 位图数据信息结构
 25 */
 26 #pragma pack(1)
 27 typedef struct tagBITMAPINFOHEADER
 28 {
 29     unsigned long biSize;//该结构的大小
 30     long biWidth;//文件宽度
 31     long biHeight;//文件高度
 32     unsigned short biPlanes;//平面数
 33     unsigned short biBitCount;//颜色位数
 34     unsigned long biCompression;//压缩类型
 35     unsigned long biSizeImage;//DIB数据区大小
 36     long biXPixPerMeter;
 37     long biYPixPerMeter;
 38     unsigned long biClrUsed;//多少颜色索引表
 39     unsigned long biClrImporant;//多少重要颜色
 40 }fileInfo;
 41 #pragma pack()
 42 /*
 43 调色板结构
 44 */
 45 #pragma pack(1)
 46 typedef struct tagRGBQUAD
 47 {
 48     unsigned char rgbBlue; //蓝色分量亮度
 49     unsigned char rgbGreen;//绿色分量亮度
 50     unsigned char rgbRed;//红色分量亮度
 51     unsigned char rgbReserved;
 52 }rgbq;
 53 #pragma pack()
 54 
 55 int main()
 56 {
 57     /*存储RGB图像的一行像素点*/
 58     unsigned char ImgData[3000][3];
 59     /*将灰度图的像素存到一个一维数组中*/
 60     unsigned char ImgData2[3000];
 61     int i,j,k;
 62     FILE * fpBMP,* fpGray;
 63     fileHeader * fh;
 64     fileInfo * fi;
 65     rgbq * fq;
 66     
 67     if((fpBMP=fopen("G:/vc6.0/work/21.bmp","rb"))==NULL)
 68     {
 69         printf("打开文件失败");
 70         exit(0);
 71     }
 72     
 73     if((fpGray=fopen("G:/vc6.0/work/22.bmp","wb"))==NULL)
 74     {
 75         printf("创建文件失败");
 76         exit(0);
 77     }
 78     
 79     fh=(fileHeader *)malloc(sizeof(fileHeader));
 80     fi=(fileInfo *)malloc(sizeof(fileInfo));
 81     //读取位图头结构和信息头
 82     fread(fh,sizeof(fileHeader),1,fpBMP);
 83     fread(fi,sizeof(fileInfo),1,fpBMP);
 84     //修改头信息
 85     fi->biBitCount=8;
 86     fi->biSizeImage=( (fi->biWidth*3+3)/4 ) * 4*fi->biHeight;
 87     //fi->biClrUsed=256;
 88     
 89     fh->bfOffBits = sizeof(fileHeader)+sizeof(fileInfo)+256*sizeof(rgbq);
 90     fh->bfSize = fh->bfOffBits + fi->biSizeImage;
 91     
 92     //创建调色版
 93     fq=(rgbq *)malloc(256*sizeof(rgbq));
 94     for(i=0;i<256;i++)
 95     {
 96         fq[i].rgbBlue=fq[i].rgbGreen=fq[i].rgbRed=i;
 97         //fq[i].rgbReserved=0;
 98     }
 99     //将头信息写入
100     fwrite(fh,sizeof(fileHeader),1,fpGray);  
101     fwrite(fi,sizeof(fileInfo),1,fpGray); 
102     fwrite(fq,sizeof(rgbq),256,fpGray);
103     //读取RGB图像素并转换为灰度值
104     for ( i=0;i<fi->biHeight;i++ )
105     {
106         for(j=0;j<(fi->biWidth+3)/4*4;j++)
107         {
108             for(k=0;k<3;k++)
109                 fread(&ImgData[j][k],1,1,fpBMP);
110         }
111         for(j=0;j<(fi->biWidth+3)/4*4;j++)
112         {
113             ImgData2[j]=int( (float)ImgData[j][0] * 0.114 +
114                         (float)ImgData[j][1] * 0.587 +
115                         (float)ImgData[j][2] * 0.299 );
116         }
117         //将灰度图信息写入
118         fwrite(ImgData2,j,1,fpGray);
119     }   
120         
121         free(fh);
122         free(fi);
123         free(fq);
124         fclose(fpBMP);
125         fclose(fpGray);
126         printf("success\n");
127         return 0;
128 }

结果:

posted @ 2015-06-12 11:05  雪原寸草  阅读(8713)  评论(1编辑  收藏  举报