山东轻工业学院2012届本科生毕业设计(论文)
System.IntPtr Scan0 = bmData.Scan0; byte* p = (byte*)(void*)Scan0;
int nOffset = stride - c_Bitmap.Width * 3; int nWidth = c_Bitmap.Width; int nHeight = c_Bitmap.Height; for (int y = 0; y < nHeight; ++y) {
for (int x = 0; x < nWidth; ++x) {
if (p[0] > va) {
p[0] = p[1] = p[2] = 255; } else
p[0] = p[1] = p[2] = 0; p += 3; }
p += nOffset; } }
3、效果图
图4-12 灰度化的车牌图像
图4-13 二值化的车牌图像
4、结果分析
此处车牌图片的二值化采用的是自适应阈值二值化,它根据车牌字符和车牌背景的区分,能有效地将字符突出出来,对车牌的分割有着很大的优点。
29
山东轻工业学院2012届本科生毕业设计(论文)
4.3.3 车牌字符的分割 1、原理
由于铆钉和周围其它干扰像素的原因,使得垂直投影中,铆钉会对图像的分割起干扰作用,所以要先去除铆钉和确定字符上下界。
首先将图片看成是一个平面,将图片向水平方向投影,这样有字的地方的投影值就高,没字的地方投影得到的值就低。这样会得到一根曲线,像一个又一个山头。然后,用一根扫描线从下向上扫描。这个扫描线会与图中曲线存在交点,这些交点会将山头分割成一个又一个区域。车牌图片一般是7个字符,因此,当扫描线将山头分割成七个区域时停止。然后根据这七个区域向水平线的投影的坐标就可以将图片中的七个字符分割出来。
然后对图像进行垂直投影,竖直方向从下到上扫描出6个大的间隙,再根据字符的宽度特点,确定其字符位置。
切割出字符后,将文字的外边框按比例线性放大或缩小成为规定尺寸的文字图像;简单的采用图像的放大和缩小算法,实现所有字符的同大小,为下一步识别做好准备。并将已预处理过后相应的字符归一化后后台保存起来,为下一步车牌识别准备
本文是对二值化后的车牌图像循环取得水平的白点个数,依据连续原则判断出精确车牌的上下界,在确定上下界范围中循环取得垂直的白点个数,循环从下界取值,到一定值时出现7段低于阈值时,按一定原则分割确定字符,在车牌图片加辅助线,分割字符,对字符进行归一化,依次存储并显示。
2、代码实现
if ((Xl - Xh) > 1 && (Yr - Yl) > 1)//确定边界 {
Rectangle sourceRectangle = new Rectangle(Yl, Xh, Yr - Yl, Xl - Xh);
c_Bitmap2=c_Bitmap1.Clone(sourceRectangle, PixelFormat.DontCare);
BitmapData bmData2 = c_Bitmap2.LockBits(new Rectangle(0, 0, c_Bitmap2.Width,c_Bitmap2.Height),ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
int stride2 = bmData2.Stride;
System.IntPtr Scan02 = bmData2.Scan0; byte* p2 = (byte*)(void*)Scan02;
int nOffset2 = stride2 - c_Bitmap2.Width * 3;
30
山东轻工业学院2012届本科生毕业设计(论文)
int nWidth2 = c_Bitmap2.Width; int nHeight2 = c_Bitmap2.Height; for (int y = 0; y < nHeight2; ++y) {
for (int x = 0; x < nWidth2; ++x) {
if (x == (Yr1[0] - Yl) || x == (Yl1[0] - Yl) || x == (Yr1[1] - Yl) || x == (Yl1[1] - Yl) || x == (Yr1[2] - Yl) || x == (Yl1[2] - Yl) || x == (Yr1[3] - Yl) || x == (Yl1[3] - Yl) || x == (Yr1[4] - Yl) || x == (Yl1[4] - Yl) || x == (Yr1[5] - Yl) || x == (Yl1[5] - Yl) || x == (Yr1[6] - Yl) || x == (Yl1[6] - Yl) || x == (Yr1[7] - Yl) || x == (Yl1[7] - Yl))
{
if (x != 0) {
p2[2] = 255; p2[0] = p2[1] = 0; } } p2 += 3; }
p2 += nOffset2; }
c_Bitmap2.UnlockBits(bmData2); panel2.Invalidate();
if ((Xl - Xh) > 1 && (Yr1[0] - Yl1[0]) > 1)//字符归一化 {
Rectangle sourceRectangle0 = new Rectangle(Yl1[0], Xh, Yr1[0] - Yl1[0], Xl - Xh);
z_Bitmap0=c_Bitmap1.Clone(sourceRectangle0, PixelFormat.DontCare);
z_Bitmaptwo[0]=c_Bitmap.Clone(sourceRectangle0, PixelFormat.DontCare);
objNewPic = new System.Drawing.Bitmap(z_Bitmaptwo[0], 9, 16); z_Bitmaptwo[0] = objNewPic; panel10.Invalidate(); }
31
山东轻工业学院2012届本科生毕业设计(论文)
3、效果图
图4-14车牌字符指示图像
图4-15 字符分割后的图像 图4-16经过归一化的字符
4、结果分析
本文采用系统切割出来的字符作为模板,对于一些实际情况有着良好的适应性,提高字符识别率。
4.4 字符识别模块 1、原理
字符识别方法目前主要有基于模板匹配算法和基于人工神经网络算法。 我们选用基于模板匹配算法首先将分割后的字符二值化,并将其尺寸大小缩放为字符数据库中模板的大小,然后与所有的模板进行匹配,最后选最佳匹配作为结果。
运行该程序后,会将上一步存储的字符与已存好的模板进行匹配,把其像素点的相同点数和白点的个数作为依据,采用AD算法,求提取的模板和原来模板像素点灰度绝对值之差,并统计差的和值,将该和作为2幅图像的距离,选择距离最小者输出结果,能够针对一部分车牌图像进行很好的识别。
2、代码实现
for (int i = 0; i < 39; i++)//车牌字母或数字比较识别 {
byte* p = (byte*)(void*)Scan; BitmapData gb);
int stride1 = bmData1.Stride;
32
bmData1=font[i].LockBits(new Rectangle(0, 0,
font[i].Width,font[i].Height),ImageLockMode.ReadWrite,PixelFormat.Format24bppR
山东轻工业学院2012届本科生毕业设计(论文)
System.IntPtr Scan1 = bmData1.Scan0; byte* p1 = (byte*)(void*)Scan1; int nOffset1 = stride1 - font[i].Width * 3; int nWidth1 = font[i].Width; int nHeight1 = font[i].Height; int ccc0 = 0, ccc1 = 0; lv = 0;
}
3、效果图
for (int y = 0; y < nHeight; ++y) {
for (int x = 0; x < nWidth; ++x) {
if ((p[0] - p1[0]) != 0) lv++;
if (p[0] == 255) { ccc0++; } if (p[1] == 255) { ccc1++; } p1 += 3; p += 3; }
p1 += nOffset; p += nOffset; }
lv = lv + Math.Abs(ccc0 - ccc1);//模板匹配 if (lv < lc) { lc = lv; con = i;
zf[j] = xianshi[con]; }
font[i].UnlockBits(bmData1); 33