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 }
结果: