图像验证码的识别(一)——浅谈bmp文件格式

时间:2021-12-21 10:03:37

上个学期,用openCV做了一个OCR的课程设计,主要就是对图片验证码进行识别。最近新开学闲来无事,想想还是整理一下比较好,不过毕竟过了一个寒假,有些东西可能记得不是太清,如果有错误还望多多包涵。首先还是用具体的bmp格式来介绍一下图片的基本知识。

在计算机图形学里,位图就是一个像素的矩阵,矩阵中的每一个点都是各种颜色的点,最后总体上来看就是一副图像。如何显示每一个像素的具体颜色,有很多种颜色空间,最常见的就是RGB,每一个像素含有三个分量——R,G,B,分别代表红、绿和蓝三种颜色,三个分量的值的具体的大小就代表三种颜色的深浅,而最终该像素显示出来的颜色就是这三种颜色混合而成的。

BMP图片种每个像素的颜色就是以位图的形式储存的,bmp文件主要是由三部分组成,最开始是文件头,54个字节固定大小,包含了图片的最基本信息,包括图片的分辨率、数据位长度等信息;第二部分是调色板,如果位图长度位24位那么就不需要调色板;文件的最后也是位图文件的关键部分就是每一个像素的颜色数据。

所有的BMP位图文件的文件头的格式都是一样的,54个字节,分别为文件头(14个字节)和信息头(40个字节),文件头被封装在BITMAPFILEHEADER数据结构中,信息头则封装在BITMAPINFOHEADER中。

文件头顾名思义,保存在文件的最开始,BMP文件载入内存后最前面的54个字节就是文件头了,文件头存储着该BMP文件的重要信息,具体的数据结构在下面给出:

//file header from 0 to 13 byte
typedef struct _BITMAPFILEHEADER
{
u_int16_t bfType; //file type
u_int32_t bfSize; //file size
u_int16_t bfReserved1; //reserved word 1
u_int16_t bfReserved2; //reserved word 2
u_int32_t bfOffBits; //offset of bit date
}FileHeader;

//info header from 14 to 53 byte
typedef struct _BITMAPINFOHEADER
{
u_int32_t biSize; //bytes of this struct
u_int32_t biWidth; //width in pixel
u_int32_t biHeight; //height in pixel
u_int16_t biPlanes;
u_int16_t biBitCount; //bit need of each pixel
u_int32_t biCompression; //type of bitmap compression
u_int32_t biSizeImage; //size of bitmap in byte
u_int32_t biXPelsPerMeter;
u_int32_t biYPelsPerMeter;
u_int32_t biClrUsed; //number of color used in color table
u_int32_t biClrImportant; //important color
}InfoHeader;
文件头和信息头的数据结构里面的变量具体表示什么意义,都有注释。其中比较重要的就是位图文件的width和height,每一个像素颜色是多少位(BitCount)等。如果一个像素的颜色有1位,那么这个图像就是二值图像,黑白两色;如果一个像素颜色有8位,那么这个图像一般就是灰度图,一共有256个值可选;如果是24位,那么就是较为常见的彩色图像。由于代码是在Linux环境下编写的,所以这里用到的数据类型都是Linux的数据类型,比如4字节就是u_int32_t,在windows环境下,长度也是一样的,只是类型的声明不太一样。


接下来是调色板,除了24位BMP图片没有调色板之外,其他情况下一般都有调色板,如果一个位图文件是8位的,那么调色板的大小应该是2^8=256种。使用调色板的好处就是用什么颜色存储什么颜色,每一种颜色都对应一个号,标记每个像素的颜色的时候,只需要存储这个颜色在调色板中的id,而不需要将该颜色所有的rgb分量都存储进来。比如在256色灰度图种,每一个灰度值对应的r、g和b都是相等的,分别取0-255(灰度位1则rgb都为1),这样每个像素只需要8位便可以表示该像素的颜色了。

调色板的数据结构如下:

//quad
typedef struct _RGBQUAD
{
u_int8_t rgbBlue;
u_int8_t rgbGreen;
u_int8_t rgbRed;
u_int8_t rgbReserved;
}RgbQuad;

最后就是具体的每个像素对应的颜色值了,根据文件头的属性,图片从左上角第一个从左到右、从上到下一排一排,每个像素的位图值以此排列。