菜鸟学习笔记供新手学习参考,一个有着很多限制的小程序,大神路过多多指点。
不废话,正题如下:
bmp验证码识别的流程大概分为:
1、获取bmp图片中识别需要用到的数据,包括像素高度、像素宽度以及位图数据。
2、对获取的数据进行必要的处理,包括灰度化、二值化、去噪等。
3、对处理后的数据(一个二值化的数组)进行扫描,分割出各个字符(即确定多对数组下标)。
4、建立字符模板库,将分割出的字符与模板一一对比,找出对应的字符。
下面具体讲解:
1、获取数据。
bmp文件结构与读取遍地都是,细节不赘述。
需要注意:1)简单识别用到的也就是biWidth(19-22字节),biHeight(23-26字节),以及位图数据(>54字节)。
2)位图数据是倒着存放,读取或处理的时候要进行处理。
位图数据每行会自动填充字节为4的倍数,读取或处理时最好跳过相应数目的字节。
3)每个像素有3个分量RGB,对应3个字节。
4)关于调色板:由于现在基本都是24位真彩图,所以这个基本可以不考虑,所以才是读取54字节以后的为位图数据。
调色板个人理解: 类似超市寄存物品,每个格子就是一种颜色,通过你的编号(即位图数据,注
意这里每个像素不是3字节,而是因多少位的图片而异),拿到你想要的颜色。
// 提供方法:
// 1、取得图片信息。
// 2、取得图片数据。
class readBmp
{
public:
bool getWidth(long &); //得到位图的宽
bool getHeight(long &); //得到位图的高
bool getBit(int &); //得到位图位数
bool getData(bit_t *&); //读取文件的颜色信息,即像素部分,即rgb信息
readBmp(const char *path);
~readBmp();
private:
int bitWidth;
int bitHeight;
int bitBit;
bool bitReadSuccess; //记录构造函数里bmp文件是否成功读取
void distroy();
bit_t *tmpData; //从文件读出的数据地址
bool isInforExisted(void); //判断bmp文件是否成功读取
};
/*
在构造函数里读取所需的文件信息,包括像素高度、宽度、和位图数据
自己申请的空间在析构函数释放
*/
readBmp::readBmp(const char *path)
{
ifstream bmpFile(path, ios::in | ios::binary); //创建一个读取文件流对象, 不自动生成不存在文件,二进制方式打开
bitReadSuccess = bmpFile.good(); //判断文件是否成功打开
if(true == bitReadSuccess)
{
bmpFile.seekg(18, ios::beg); //bmp文件结构中WIDTH 和 HEIGHT为long类型,在19-26字节
bmpFile.read((char *)(&bitWidth), 4); //由于read方法参数类型限制,要将第一个参数如左处理
//64位系统g++ long 为8字节,不能用sizeof(long)获取字节数,否则文件指针偏移量过大,读取过多
bmpFile.read((char *)(&bitHeight), 4);
bmpFile.seekg(2, ios::cur);
bmpFile.read((char *)(&bitBit), sizeof (bitBit));
if (bitBit != 24) //暂时只考虑24位图片的读取,2、4、8位的可以以后扩充
{
cout << "非24位图片,请选择合适的图片重试!" << endl;
}
else
{
long count = 0;
bmpFile.seekg(22, ios::cur);
tmpData = new bit_t[bitWidth * bitHeight * 3];
long skipWidth = (4 - bitWidth*3%4)%4; //计算每行读取时要skip的字节数
for(int i = bitHeight - 1; i >= 0; i--)
{
for( int j = 0; j < bitWidth * 3; j++)
bmpFile.get(tmpData[count+