#202. zyy的色环电阻

内存限制:256 MiB 时间限制:1000 ms 输入文件:res.bmp 输出文件:result.txt
题目类型:传统 评测方式:文本比较
上传者: zyy

题目描述

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;  	// BMP文件头
BMPINF BMPInfo;             // 位图信息头

if ((fp = fopen("filename.bmp", "rb")) == NULL){  //rb代表以二进制读取
	printf("Failed to open the BMP file!\n");
	exit(0);
}

// 格式:fread(目的地址,数据大小,读取数量,文件指针)
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. 处理三维数组,获得电阻值

这里就留给大家自由发挥了。我们保证电阻一定横放(正),两侧引线一定连接在图片最边缘与电阻最边缘处,色环与电阻整体构成平齐的长方形,如示例图所示。可以理解为,除电阻的位置、图像大小、色环颜色、色环左右位置外,测试数据与样例完全一致。

标准色环电阻对照表如下:

本题为四色环电阻,忽略中间未标箭头一列。

输入格式

一张24位BMP图片,输入文件名为res.bmp,图片像素尺寸在500*500以内,图中出现的13种颜色的RGB值如下

颜色 颜色RGB值{R,G,B}
黑色(以及两侧引线) {0,0,0}
棕色 {165,42,42}
红色 {255,0,0}
橙色 {255,128,0}
黄色 {255,255,0}
绿色 {0,255,0}
蓝色 {0,0,255}
紫色 {128,0,255}
灰色 {192,192,192}
白色(以及背景) {255,255,255}
浅蓝色(电阻壳体) {0,255,255}
金色 {255,201,14}
银色 {128,128,128}

输出格式

文件输出,输出文件名result.txt

一行,格式如下

R = [电阻值] ohm (within [误差值]%)

其中,电阻值若为整数,输出整数;若为小数,保留两位小数。误差值请严格按照对应表中给出的值和格式输出

样例

【样例输入1】

右键另存为可下载(若做修改,请保证格式为24位BMP格式)

【样例输出1】

R = 12000 ohm (within 5%)

数据范围与提示

BMP结构体定义:

#pragma pack(1)
typedef struct BMP_FILE_HEADER {
    WORD bType;      // 文件标识符
    DWORD bSize;     // 文件的大小
    WORD bReserved1; // 保留值,必须设置为0
    WORD bReserved2; // 保留值,必须设置为0
    DWORD bOffset;   // 文件头的最后到图像数据位开始的偏移量
} BMPFILEHEADER;     // 14 字节

/* 位图信息头 */
typedef struct BMP_INFO {
    DWORD bInfoSize;            // 信息头的大小
    DWORD bWidth;               // 图像的宽度
    DWORD bHeight;              // 图像的高度
    WORD bPlanes;               // 图像的位面数
    WORD bBitCount;             // 每个像素的位数
    DWORD bCompression;         // 压缩类型
    DWORD bmpImageSize;         // 图像的大小,以字节为单位
    DWORD bXPelsPerMeter;       // 水平分辨率
    DWORD bYPelsPerMeter;       // 垂直分辨率
    DWORD bClrUsed;             // 使用的色彩数
    DWORD bClrImportant;        // 重要的颜色数
} BMPINF;            // 40 字节
通告标题

通告内容

已知晓