纵使汽车车牌识别的方法有很多种,这里只简单介绍一种较为简单和准确的方法。
关键的一步是定位到车牌,车牌和汽车背景不同的是它们的纹理有很大的区别,大多数的汽车车身和背景的纹理为横向纹理,而车牌字符的是竖向纹理,关于车牌定位有以下重要的几步:
1.预处理
为了进行一些滤波和梯度增强的处理,以达到滤除噪声和垂直方向上的增强。
2.垂直方向边缘检测并且二值化的处理
使用效率较高的Sobel边缘检测算子对图像进行垂直边缘检测,通过字符的竖向纹理特征检测到汽车车牌字符,对得到的边缘图像进行二值化,排除一些噪声,并增强边缘字符。
3.形态学变换
汽车图像还存在一些竖向的纹理,我们需要排除这些干扰信息,并且把临近的字符边缘连通起来,这一阶段的处理主要使用了形态学的操作,闭合运算和开启运算。
4.筛选
大多数的图像经过形态学变换后可以达到一个较为满意的效果,但是由于图像背景本身存在一些特殊的纹理,也可能留下一些没有滤除的边缘,此时我们就需要进行聚类和筛选,选取一个标准来判断连通域,再根据车牌的形状大小来判断是否为车牌区。
1.车牌提取
首先进行灰度化
CvCvtColor (image,grayScale,CV_BGR2GRAY);
2.竖向边缘检测
车牌上的数字都有很锐利的边缘,这些边缘大多都是纵向的,因此可以通过这;一步来去除图像上的无用的信息。
sobel=cvCreateImage(cvGetSize(grayScale),IPL_DEPTH_16S,1);//创建一张深度为16位有符号(-65536~65535)的图像区域保持处理结果
cvSobel(grayScale,sobel,2,0,8);//进行X方向的sobel检测,算子的大小选择了8*8
IplImage * temp=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);//最后将图像格式8位深度进行下一步处理。
cvConvertScale(sobel,temp,0.00390625,0);
3.自适应二值化处理
二值化的处理强化了锐利的边缘,进一步去除图像中的无用的信息,使用过程中主要注意如何选取阈值。
cvThreshold(sobel,threshold,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU);//最后的参数即为自适应算法。
4.形态学的处理
涉及膨胀和腐蚀,通过膨胀链接相近的图像区域,通过腐蚀去除孤立细小的色块,通过这一操作后,将所有的车牌字符连接起来,为接下来的车牌轮廓识别做基础,因为字符是横向排列的,所以只需要对这些字符进行横向的处理。
IpConvKernel * kernal=cvCreateStructuringElementEx(3,1,1,0,CV_SHAPE_RECT);//自定义1*3的X方向膨胀腐蚀
cvDilate(threshold,erode_dilate,kernal,2);//x方向膨胀连通数字
vErode(erode_dilate,erode_dilate,kernal,4);//x方向腐蚀去除碎片
cvDilate(threshold,erode_dilate,kernal,2);//x方向膨胀回复状态
kernal=cvCreateStructuringElementEx(3,1,1,0,CV_SHAPE_RECT); //自定义1*3的Y方向膨胀腐蚀
cvDilate(threshold,erode_dilate,kernal,1);//Y方向膨胀连通数字
vErode(erode_dilate,erode_dilate,kernal,2);//Y方向腐蚀去除碎片
5.轮廓的查找与筛选
通过轮廓查找,定位到车牌的字符区域,在上一步的操作中我们将原始图片中在X方向排列紧密的纵向边缘区域连成了一个矩形区域,根据对车牌特点的对这些矩形区域进行进一步的筛选,最终确定车牌所在的矩形区域。
轮廓检测
IplImage *copy=cvCloneImage(img);
CvMemStorage * storage=cvCreateMemStorage();
CvSeq * contours;
cvFindContours(copy,storage,&contours);
while(contours!=null)
{
rects.push_back(cvBoundingRect(contours));
contours=contours->h_next
}
使用list存储全部查找到的CvRect,矩形的筛选算法类似
6.字符提取
字符的提取步骤与车牌提取的步骤类似,不同的是字符提取中不需要再做形态学的处理,依旧是灰度化->二值化->轮廓检测->自定义筛选->定位,除了自定义筛选和去除边框铆钉这一步骤外,因为最容易导致字符提取失败的就是亮色的边框和铆钉,他们和车牌字母连通在一起,很容易导致轮廓检测失败。
(1)去除边框
首先对图像进行Y方向的逐步裁剪,直至轮廓检测可以检测到超过5个轮廓,从而保证了不会与铆钉链接的中间的几个字符可以通过轮廓检测识别出来。
(2)去除铆钉
根据识别出来的几个字符矩形轮廓确定车牌所有字符的上下界,根据其切割图像。
(3)矩形筛选
(4)中文字符定位
中文字符由于有些是非单连通的,在筛选的时候可能会被筛选掉,即使没有被筛选掉,所得的矩形也可能没有包含所有的字体,在字符提取的最后一步需要重定位中文字符的矩形截取框,大致的算法是以第二个字符的矩形轮廓为基准,大小不变,y坐标不表白,根据自附件平均间距确定x坐标。
double d=lastChar.x+0.5*lastChar.width-llChar.x-llChar.width*0.5-avgWidth
7.字符匹配
进行匹配之前首先要确定一套标准字符模板作为参考,然后将提取出来的字符图片与每个模板进行某种算法的匹配,求得一个匹配值,最终将最佳匹配结果作为该字符图片代表的字符,
(1)逐点匹配
经过处理的带匹配的图片与模板图片此时大小相同,且都为二值化图,遍历所有的像素点,记录两张途中中值不同的像素点个数,除以全部像素数量为匹配率,越接近0越匹配。
(2)近似区分
针对一些容易混淆的字符还需要进一步区分,比如B和8,如果在逐点匹配中不能马上确认,就需要进行近似区分。