基于BP神经网络的字符识别.docx
《基于BP神经网络的字符识别.docx》由会员分享,可在线阅读,更多相关《基于BP神经网络的字符识别.docx(200页珍藏版)》请在冰点文库上搜索。
基于BP神经网络的字符识别
1系统简介
该系统是为了辨认识别图像中的数字而设计的,它通过对图片的一系列处理,最后识别得出图片中显示的数字。
系统既可以单独使用,也可以把它作为一个识别系统的软件核心应用到车牌识别等系统中去。
2系统基本技术要求
下面是系统具体要达到的基本技术要求
(1)输入图片中可以含有多个数字;
(2)数字的识别准确率大于90%;
(3)每张图片的处理时间(识别时间)不能大于1秒;
(4)对图片噪声具有较强的适应性;
(5)系统要能长时间无故障运行;
(6)系统的操作要求简单。
3系统中用到的关键技术
在本系统中用到了好多图像处理中的相关技术:
比如灰度化、二值化、图像内容自动调整、去离散点、图像的缩放、细化、曲线平滑、曲线去枝桠操作等,最后还使用了神经网络对提取到的数字信息进行分析判断。
4系统软硬件平台
4.1系统的硬件平台
因为系统运行的过程当中,主要进行的都是图像处理,在这个过程当中要进行大量的数据处理,所以处理器和内存要求比较高,CPU要求主频在600hz以上(含600hz),内存在128兆以上(含128兆)。
.4.2系统的软件平台
系统可以运行于任何一台装有Windows98、Windows2000或者WindowsXP的机子上。
程序调试时,需要使用MicrosoftVisualC++6.0(SP6)。
5系统实现
系统在实现的过程当中,先分解成两个大块,就是图像预处理模块和数字识别模块。
其中图像像预处理块在对图像进行了一系列变换后把最后提取到的数字字符提交给数字识别模块,然后进行识别并给处结果。
在这里用到了很多先进的图像预处理技术及神经网络技术。
5.1系统流程图
本系统总的流程结构如图11-1所示。
图11-1系统总流程图
其中图像预处理的流程如图11-2所示。
图11-2图像预处理流程图
神经网络数字识别的具体流程如图11-3所示。
图11-3神经网络数字识别流程图
5.2程序实现
整个系统的程序实现分为图像预处理和神经网络识别两大模块。
在图像预处理的过程当中,我们采用了许多图像处理的技术,最后把每个数字的特征提取出来。
这些技术包括图像数据读取、图像的灰度化、二值化、图像的调整、离散噪声点的去除、字符的切分、图像的缩放、字符的细化、字符的平滑、图像的求梯度等图像处理技术,最后是数字字符特征的提取。
其结果再利用神经网络(这里我们选用BP网络)进行字符识别。
利用神经网络进行字符识别的过程主要包括网络的训练、数据的读取、字符的判定、结果的输出。
下面按照程序执行的顺序介绍整个程序并逐一分析每一步的关键代码。
最后简要讲述一下程序的使用方法、注意事项以及本章小结。
1.图像数据的读取、保存与屏幕显示等基本函数
要进行图像分析和处理首先就要得到图像的数据,这些数据包括图像的宽、高、每个象素点的颜色值。
因为每种文件都有它自己的存放格式,下面简单介绍BMP文件的存放格式。
本程序采用的输入图像即为bmp位图。
BMP(bitmap的缩写)文件格式是Windows本身可以直接提供读取支持的位图文件格式。
一个BMP格式的文件通常有.BMP的扩展名,但有一些是以.rle为扩展名的,rle的意思是行程长度编码(runlengthencoding)。
这样的文件意味着其使用的数据压缩方法是BMP格式文件支持的两种rle方法中的一种。
BMP文件可用每象素1、4、8、16或24位来编码颜色信息,这个位数称作图像的颜色深度,它决定了图像所含的最大颜色数。
一幅1-bpp(位每象素,bitperpixel)的图像只能有两种颜色。
而一幅24-bpp的图像可以有超过16兆种不同的颜色。
一个典型BMP文件的结构。
以256色也就是8-bpp为例,文件被分成四个主要的部分:
一个位图文件头,一个位图信息头,一个颜色表(又称为色表)和位图数据本身。
位图文件头
位图文件头包含关于这个文件的信息。
如从哪里开始是位图数据的定位信息、文件大小等等。
以下是位图文件头结构的定义:
typedefstructtagBITMAPFILEHEADER
{//bmfh
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
}BITMAPFILEHEADER;
其中的bfType值应该是“BM”(0x4d42),标志该文件是位图文件。
bfSize的值是位图文件的大小。
位图信息头
位图信息头包含了单个像素所用字节数以及描述颜色的格式,此外还包括位图的宽度、高度、目标设备的位平面数、图像的压缩格式。
以下是位图信息头结构的定义:
typedefstructtagBITMAPINFOHEADER{//bmih
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
}BITMAPINFOHEADER;
下面是对结构体当中各个成员的说明:
biSize
结构BITMAPINFOHEADER的字节数,即sizeof(BITMAPINFOHEADER)*
biWidth
以像素为单位的图像宽度*
biHeight
以像素为单位的图像长度*
biplanes
目标设备的位平面数
biBitCount
每个像素的位数
biCompression
图像的压缩格式(这个值几乎总是为0)
biSizeImage
以字节为单位的图像数据的大小(对BI_RGB压缩方式而言)
biXPelsPermeter
水平方向上的每米的像素个数
biYPelsPerMeter
垂直方向上的每米的像素个数
biClrused
调色板中实际使用的颜色数
这个值通常为0,表示使用biBitCount确定的全部颜色,例外是使用的颜色的数目小于制定的颜色深度的颜色数目的最大值。
biClrImportant
现实位图时必须的颜色数
这个值通常为0,表示所有的颜色都是必需的
对于其中的biBitCount,分别有以下意义:
0,用在JPEG格式中
1,单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片
4,16色图
8,256色图,通常说的灰度图
16,64K图,一般没有调色板,图像数据中每两个字节表示一个像素,5个或6个位表示一个RGB分量
24,16M真彩色图,一般没有调色板,图像数据中每3个字节表示一个像素,每个字节表示一个RGB分量
32,4G真彩色,一般没有调色板,每4个字节表示一个像素,相对24位真彩图而言,加入了一个透明度,即RGBA模式。
颜色表
颜色表(文中简称色表)一般是针对16位以下的图像而设置的,对于16位和16位以上的图像,由于其位图像素数据中直接对对应像素的RGB(A)颜色进行描述,因而省却了调色板。
而对于16位以下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。
颜色表的作用就是创建调色板。
对显示卡来说,如果它不能一次显示超过256种颜色,读取和显示BMP文件的程序能够把这些RGB值转换到显示卡的调色板来产生准确的颜色。
颜色表的颜色表项结构的定义如下:
typedefstructtagRGBQUAD{//rgbq
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}RGBQUAD;
其中需要注意的问题是,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。
位图数据
BMP文件的位图数据格式依赖于编码每个象素颜色所用的位数。
对于一个256色的图像来说,每个象素占用文件中位图数据部分的一个字节。
象素的值不是RGB颜色值,而是文件中色表的一个索引。
所以在色表中如果第一个R/G/B值是255/0/0,那么象素值为0表示它是鲜红色,象素值按从左到右的顺序存储,通常从最后一行开始。
所以在一个256色的文件中,位图数据中第一个字节就是图像左下角的象素的颜色索引,第二个就是它右边的那个象素的颜色索引。
如果位图数据中每行的字节数是奇数,就要在每行都加一个附加的字节来调整位图数据边界为16位的整数倍。
并不是所有的BMP文件结构都像表中所列的那样,例如16和24-bpp,文件就没有色表,象素值直接表示RGB值,另外文件私有部分的内部存储格式也是可以变化的。
例如,在16和256色BMP文件中的位图数据采用rle算法来压缩,这种算法用颜色加象素个数来取代一串颜色相同的序列,而且,Windows还支持OS/2下的BMP文件,尽管它使用了不同的位图信息头和色表格式。
为了减小运算的数据量,本程序使用256色BMP文件作为输入。
近年来,一种后缀名为jpg的位图凭借较高的压缩比和不俗的品质,并借助网络的优势而迅速成为图像/图形行业事实上的工业标准。
本文没有采用jpg位图,但在这里也简要的介绍一下,以供读者参考。
jpg是24位的图像文件格式,也是一种高效率的压缩格式,文件格式是JPEG(联合图像专家组)标准的产物,该标准由ISO与CCITT(国际电报电话咨询委员会)共同制定,是面向连续色调静止图像的一种压缩标准。
其最初目的是使用64Kbps的通信线路传输720×576分辨率压缩后的图像。
通过损失极少的分辨率,可以将图像所需存储量减少至原大小的10%。
由于其高效的压缩效率和标准化要求,目前已广泛用于彩色传真、静止图像、电话会议、印刷及新闻图片的传送上。
但那些被删除的资料无法在解压时还原,所以*.jpg文件并不适合放大观看,输出成印刷品时品质也会受到影响。
不过,普通用户不必担心,因为*.jpg的压缩算法十分先进,它对图形图像的损失影响不是很大,一幅16M(24位)的*.jpg/*.jpeg图像看上去与照片没有多大差别,非专业人士甚至无法分辨。
同样一幅画面,用*.jpg格式储存的文件是其他类型图形文件的1/10~1/20。
一般情况下,*.jpg文件只有几十KB,而色彩数最高可达到24位,所以它被广泛运用在Internet上,以节约宝贵的网络传输资源。
同样,为了在一张光盘上储存更多的图形图像,CD出版商也乐意采用*.jpg格式。
目前,网上已经有了很多jpg图像的编解码的算法,限于篇幅,本文就不再赘述。
如果要使用jpg格式的图像,那么请先用画图软件如ACDSEE、PHOTOSHOP将其转化为256色bmp位图格式。
另外,较常用到的图像格式还有gif、tiff、png等等。
由于本文的核心主要集中在图像的预处理和BP神经网络识别部分,就不在图像格式上耗费精力了。
读者需要进一步了解图像格式的可以详细查阅相关资料。
在图像预处理部分的图像数据读取部分,作者使用了微软提供的一个图像函数库dibapi.h和dibapi.cpp,里面已经含有一些基本的图像处理函数,作者在此就不再列举源代码,而紧紧将其接口加以描述,以使读者清晰每个函数的作用。
同时作者自己对该库又加以扩充以满足本程序的需要。
文中没有贴出而程序中又用到的代码都在本书的附带光盘中可以找到。
本小节所有的函数定义及声明位于dibapi.h、dibapi.cpp、mydiblib.h中。
首先来看7个图像数据读取/存储/创建以及图像基本信息获取函数。
图像数据读取/保存由函数ReadDIBFile、SaveDIB、FindDIBBits、DIBWidth、DIBHeight、DIBNumColors完成,其调用接口如下:
(1)ReadDIBFile函数
函数原型:
HDIBWINAPIReadDIBFile(CFile&file);
参数:
CFile&file-要读取得文件文件CFile
返回值:
HDIB-成功返回DIB的句柄,否则返回NULL。
说明:
该函数将指定的文件中的DIB对象读到指定的内存区域中。
除文件头之外的内容都将被读入内存。
HDIB即此内存区域的指针
(2)SaveDIB函数
函数原型:
BOOLWINAPISaveDIB(HDIBhDib,CFile&file);
参数:
HDIBhDib-要保存的DIB
CFile&file-保存文件CFile
返回值:
BOOL-成功返回TRUE,否则返回FALSE或者CFileException
说明:
该函数将指定的DIB对象保存到指定的CFile中。
该CFile由调用程序打开和关闭。
(3)FindDIBBits函数
函数原型:
LPSTRWINAPIFindDIBBits(LPSTRlpbi);
参数:
LPSTRlpbi-指向DIB对象的指针
返回值:
LPSTR-指向DIB图像象素起始位置
说明:
该函数计算DIB中图像象素数据区的起始位置,并返回指向它的指针。
[注]LPSTR指针为指向字符串的32位的指针。
在对256色图像进行象素操作时,可以用(BYTE*)或(unsignedchar*)强制将其转换为8位的指针
(4)DIBWidth函数
函数原型:
DWORDWINAPIDIBWidth(LPSTRlpDIB)
参数:
LPSTRlpbi-指向DIB对象的指针
返回值:
DWORD-DIB中图像的宽度
说明:
该函数返回DIB中图像的宽度。
对于Windows3.0DIB,返回BITMAPINFOHEADER中的biWidth值;对于其他返回BITMAPCOREHEADER中的bcWidth值。
(5)DIBHeight函数
函数原型:
DWORDWINAPIDIBHeight(LPSTRlpDIB)
参数:
LPSTRlpDIB-指向DIB对象的指针
返回值:
DWORD-DIB中图像的高度
说明:
该函数返回DIB中图像的高度。
对于Windows3.0DIB,返回BITMAPINFOHEADER中的biHeight值;对于其他返回BITMAPCOREHEADER中的bcHeight值。
(6)DIBNumColors函数
函数原型:
WORDWINAPIDIBNumColors(LPSTRlpbi)
参数:
LPSTRlpbi-指向DIB对象的指针
返回值:
WORD-返回调色板中颜色的种数
说明:
该函数返回DIB中调色板的颜色的种数。
对于单色位图,返回2,对于16色位图,返回16,对于256色位图,返回256;对于真彩色位图(24位),没有调色板,返回0。
以上6个函数是在图像处理过程中读取/保存图像以及获取图像基本信息的6个最基本的函数。
还有一个NewDIB函数是作者自己编写的,用来建立一个新的DIB。
此函数非常有用,可以十分便利的根据所提供的要创建的位图的基本信息(高度、宽度、颜色位数)来开辟内存,并自动完成位图信息头的填充工作。
(7)NewDIB函数
其完整程序代码及注释介绍如下:
/*******************************************************************
*函数名称:
*NewDIB()
*
*参数:
*width-将要创建DIB的宽
*height-将要创建DIB的高
*biBitCount-将要创建DIB的位数。
比如,如果要创建256色DIB,则此值为8
*
*返回值:
*HDIB-成功返回DIB的句柄,否则返回NULL。
*
*说明:
*该函数指定宽、高、颜色位数来创建一个新的DIB,并返回其句柄
*
***************************************************************/
HDIBWINAPINewDIB(longwidth,longheight,unsignedshortbiBitCount)
{
//计算新建的DIB每行所占的字节数
longdwindth=(width*biBitCount/8+3)/4*4;
//新建的DIB调色板中表项的数目
WORDcolor_num;
//通过输入的biBitCount值来确定调色板的表项数目
switch(biBitCount)
{
//如果用1bit来表示一个象素那么调色板中有两个表项
case1:
color_num=2;
break;
//如果用4bit来表示一个象素那么调色板中有16个表项
case4:
color_num=16;
break;
//如果用8bit来表示一个象素,那么调色板中得表项有256中(本程序大多采用这种形式)
case8:
color_num=256;
break;
//其他的情况调色扳中没有表项,即真彩位图
default:
color_num=0;
break;
}
//计算位图数据所占的空间
//dwindth*height为象素数据所占的空间
//40为位图信息头占的空间
//color_num*4为调色板的表项所占的空间(调色板每个表项占4各个字节)
dwBitsSize=dwindth*height+40+color_num*4;
//建立指向位图文件的指针
LPSTRpDIB;
//申请存储空间,并建立指向位图的句柄
HDIBhDIB=(HDIB):
:
GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,dwBitsSize);
//如果申请空间不成功返回错误信息
if(hDIB==0)
{
returnNULL;
}
//如果申请空间成功锁定内存,并将内存的指针传给pDIB
pDIB=(LPSTR):
:
GlobalLock((HGLOBAL)hDIB);
//建立指向位图信息头结构的指针
LPBITMAPINFOlpmf=(LPBITMAPINFO)pDIB;
//给位图信息头内的各个参量赋值
//指定位图信息头结构的大小为40字节
lpmf->bmiHeader.biSize=40;
//指定新建位图的宽度
lpmf->bmiHeader.biWidth=width;
//指定新建位图的高度
lpmf->bmiHeader.biHeight=height;
//位平面数必须为1
lpmf->bmiHeader.biPlanes=1;
//确定新建位图表示颜色是要用到的bit数
lpmf->bmiHeader.biBitCount=biBitCount;
//是否进行压缩
lpmf->bmiHeader.biCompression=0;
//新建的位图中实际的位图数据所占的字节数
lpmf->bmiHeader.biSizeImage=dwindth*height;
//指定目标设备的水平分辨率
lpmf->bmiHeader.biXPelsPerMeter=2925;
//指定目标设备的垂直分辨率
lpmf->bmiHeader.biYPelsPerMeter=2925;
//新建图像实际用到的颜色数如果为0则用到的颜色数为2的biBitCount次
lpmf->bmiHeader.biClrUsed=0;
//指定新建图像中重要的颜色数,如果为0则所有的颜色都重要
lpmf->bmiHeader.biClrImportant=0;
//如果新建的图像中含有调色板,则接下来对调色板的各种颜色分量赋初始值
if(color_num!
=0)
{
for(inti=0;i{
lpmf->bmiColors[i].rgbRed=(BYTE)i;
lpmf->bmiColors[i].rgbGreen=(BYTE)i;
lpmf->bmiColors[i].rgbBlue=(BYTE)i;
}
}
//解除锁定
:
:
GlobalUnlock((HGLOBAL)hDIB);
//返回新建位图的句柄
returnhDIB;
}
以上的7个函数是打开、保存、创建位图以及获取位图基本信息的常用函数,请读者熟练掌握运用。
下面要介绍的4个函数是显示位图、清除屏幕、以及画框的函数。
其中PaintDIB函数是微软函数库提供的,由DisplayDIB函数调用,作者在此不再列举源代码,只是提供调用接口的讲解。
其他的3个作者自己编写的函数将列出详细的源代码。
(8)PaintDIB函数调用接口:
函数原型
BOOLWINAPIPaintDIB(HDC,LPRECT,HDIB,LPRECT,CPalette*pPal);
参数:
HDChDC-输出设备DC
LPRECTlpDCRect-绘制矩形区域
HDIBhDIB-指向DIB对象的指针
LPRECTlpDIBRect-要输出的DIB区域
CPalette*pPal-指向DIB对象调色板的指针
返回值:
BOOL-绘制成功返回TRUE,否则返回FALSE。
说明:
该函数主要用来绘制DIB对象。
其中调用了StretchDIBits()或者SetDIBitsToDevice()来绘制DIB对象。
输出的设备由由参数hDC指定;绘制的矩形区域由参数lpDCRect指定;输出DIB的区域由参数*lpDIBRect指定。
(9)在屏幕上显示位图的DisplayDIB函数
其完整源代码及注释介绍如下:
/***********************************************************************
函数名称:
DisplayDIB
参数:
CDC*pDC-指向当前设备上下文(DiviceContext)的指针
HDIBhDIB-要显示的位图的句柄
**********************************************************************/
voidDisplayDIB(CDC*pDC,HDIBhDIB)
{
//锁定位图并获取指向位