恰巧作业里有一道要对BMP进行卷积的题,所以干脆就写一篇文章来记录一下
BMP的基本常识
BMP取自位图Bitmap的缩写,也称为DIB(与设备无关的位图),是一种独立于显示器的位图数字图像文件格式。常见于微软视窗和OS/2操作系统,Windows GDI API内部使用的DIB数据结构与 BMP 文件格式几乎相同。
来自于此 BMP - Wikipedia
BMP的主要存储方式
此处主要用C中基本的文件指针操作来读写BMP文件,所以需要先了解BMP的文件构成(此处只列一些需要用的基本信息)。
偏移量 |
大小 |
用途 |
0x0000 |
2 Byte |
用于标识BMP和DIB文件的前缀,一般为0x42 0x4D,即ASCII的BM(在Windows下) |
0x000E |
4 Byte |
BMP Header的大小,Header中存储着此BMP文件的基本信息,此处读取的是Header末尾距离文件头的偏移量 |
0x0012 |
4 Byte |
位图的宽度,单位为像素(有符号整数) |
0x0016 |
4 Byte |
位图高度,单位为像素(有符号整数) |
0x001C |
2 Byte |
每个像素所占位数,即图像的色深。典型值为1、4、8、16、24和32 |
所以接下来先创建文件指针
1 2 3 4 5
| fpbmp = fopen(inputFileName, "rb"); if (fpbmp == NULL){ printf("Bad bmpPic!\n"); return 1; }
|
1 2 3 4
| unsigned int offset = 0; fseek(fpbmp, 10L, SEEK_SET); fread(&offset, sizeof(char), 4, fpbmp);
|
读取图片宽高
根据之前的偏移量,可以读取图片的宽高
1 2 3 4 5
| fseek(fpbmp, 18L, SEEK_SET); fread(&width, sizeof(char), 4, fpbmp); fseek(fpbmp, 22L, SEEK_SET); fread(&height, sizeof(char), 4, fpbmp);
|
读取图片位深
位深可以计算出图片的一行的宽度
1 2 3
| fseek(fpbmp, 28L, SEEK_SET); fread(&bitdep, sizeof(char), 2, fpbmp);
|
1 2 3 4 5 6
| unsigned char *fp_temp = NULL; fseek(fpbmp, 0L, SEEK_SET); fseek(fpout, 0L, SEEK_SET); fp_temp = (unsigned char *)malloc(offset); fread(fp_temp, 1, offset, fpbmp); fwrite(fp_temp, 1, offset, fpout);
|
1 2 3 4
| fseek(fpbmp, offset, SEEK_SET);
rowSize = (bitdep * width + 31) / 32; rowSize *= 4;
|
读取一行的pixel
这里需要注意的是,他的存储方式非常神奇
RGB1 RGB2 RGB3
RGB4 RGB5 RGB6
RGB7 RGB8 RGB9
假设这里有一张3x3的点阵BMP
BMP中的存储方式是这样的
像素是从下到上、从左到右保存的 而且为GBR(我也不知道为什么怎么诡异)
读取前一定要移动指针到header的末尾才能进行读取
BGR7 BGR8 BGR9
BGR4 BGR5 BGR6
BGR1 BGR2 BGR3
1 2 3 4 5 6 7 8 9 10 11
| pix = (unsigned char *)malloc(rowSize); for (int j = 0; j < height; j++) { fread(pix, 1, rowSize, fpbmp); for (int i = 0; i < width; i++) { R[height - j][i + 1] = pix[i * 3 + 2]; G[height - j][i + 1] = pix[i * 3 + 1]; B[height - j][i + 1] = pix[i * 3]; } }
|
然后就可以对R G B 三个数组里面的数据进行处理,然后输出。
输出方式十分类似不再赘述。
完成
这篇文章参考了某位大佬的博客,时间比较久远所以忘记保存来源了,鉴于网上别的博客都比较复杂,不适合刚学文件指针的小朋友们,所以记录下之前自己写的简易版
除另有声明外,本博客文章均采用 知识共享(Creative Commons) 署名 4.0 国际许可协议 进行许可。转载请注明原作者与文章出处。