zyy有很多24位BMP格式的四色色环电阻的照片,可是他并不想一个一个读这些电阻的值。他希望你能编写一个程序,来读取图片中的电阻值信息。
幸运的是,这些色环电阻照片的样式极为整齐,如下图所示。(可以右键下载后用自带“画图”软件仔细分析)
如本题图片无法显示,请按Ctrl+F5刷新页面
【本题的数据结构与处理思路】
1. BMP文件头的读取(了解即可,段末附代码)
24位BMP文件主要由三部分组成:BMP文件头(14字节),位图信息头(50字节),图像数据。
下图为BMP文件的文件结构(可以结合Huffman题目的hzip文件结构理解),WORD为双字节类型,DWORD为四字节类型,建议使用typedef实现
#include <stdint.h>
typedef uint16_t WORD;
typedef uint32_t DWORD;
以BMP文件头为例,图中bType对应的为42 4D
,bSize对应的为04 1F 00 00
,以此类推。这里应当注意的是,由于BMP采用的是小端模式,因此bSize实质上应当为00 00 1F 04
,即7940B(可以看一看和上面图片的大小是否吻合)其余参考下图(来源:知乎Lovelessing)。
不过不用担心,上述数据的读入不需要我们人工完成,我们只需要按顺序配置好BMP文件头的结构体,使用fread
统一读入即可,下面给出示例代码:
FILE *fp;
BMPFILEHEADER BMPHead;
BMPINF BMPInfo;
if ((fp = fopen("filename.bmp", "rb")) == NULL){
printf("Failed to open the BMP file!\n");
exit(0);
}
fread(&BMPHead, sizeof(BMPHead), 1, fp);
fread(&BMPInfo, sizeof(BMPInfo), 1, fp);
那么读取了BMP文件头和位图信息头有什么用呢?在本题中,验证BMP信息头的bType是否为42 4D
可帮助我们验证输入文件是否为真实的BMP文件,验证bReserved1与bReserved2是否为0可帮助我们诊断文件头信息的导入是否正确。位图信息头的bWidth和bHeight提供了图片的宽高(像素)。其余部分同学们可以自由探索,在本题中不做要求。
2. 将图像RGB数据导入到三维数组中
本题我们推荐使用三维数组作为存放像素RGB值的数据结构,其三个维度分别代表x,y,R/G/B,值为对应的R/G/B值。这里要注意的是,BMP默认从图像的左下角开始,由左至右,由下至上对文件进行保存,(在本题中影响不大)。
由于BMP文件图像数据部分对齐的特性,BMP每行占用的内存固定为4字节的倍数,即每行末尾若未对4字节对齐,需要补0。为了解决这个问题,我们引入参数offset,在图像的每行数据读取结束之后,再跳过offset个字节的空数据(1字节=sizeof(unsigned char)),代码如下:
unsigned long offset = (3 * 图像宽度) % 4;
if (offset != 0) offset = 4 - offset;
对于RGB数据,建议在二重循环的基础上,对每个像素分3次读取,每次读取1字节,此时3个字节分别为该像素的B/G/R值(为什么不是RGB?还记得上文提到的小端模式吗),代码如下
unsigned char pixVal;
fread(&pixVal, sizeof(unsigned char), 1, fp);
整体伪代码如下:
对图像数据的每一行:
对图像数据的每一列:
对B/G/R值:
从文件读入1字节的数据
把数据保存在三维数组的对应位置
从文件读入offset个字节的空白数据
把pixVal保存到三维数组的对应位置就好啦!
3. 处理三维数组,获得电阻值
这里就留给大家自由发挥了。我们保证电阻一定横放(正),两侧引线一定连接在图片最边缘与电阻最边缘处,色环与电阻整体构成平齐的长方形,如示例图所示。可以理解为,除电阻的位置、图像大小、色环颜色、色环左右位置外,测试数据与样例完全一致。
标准色环电阻对照表如下:
本题为四色环电阻,忽略中间未标箭头一列。