一、车牌检测
1. 车牌定位
这一部分的输入是原始图片,输出为可能的车牌矩形框。即将图片进行预处理,分割图片,找到可能是车牌的矩形框。作为后面SVM训练输入,定位车牌。
高斯模糊
顾名思义,其一般应用是将图像变得模糊,但同时高斯模糊也应用在图像的预处理阶段。理解高斯模糊前,先看一下平均模糊算法。平均模糊的算法非常简单。每一个像素的值都取周围所有像素(共8个)的平均值。 (高斯模糊是必要的,之后会对sobel和闭操作产生很大的影响)
openCV中的GaussianBlur函数。
灰度序列化
彩色图像是RGB三通道,取值为 HH HH HH, 每个通道是2个十六进制位,所以有256*256*256种颜色,灰度序列是指开放一个通道,取值范围为256。
openCV中的cvtColor函数。
sobel算子(laplace算子)
了解sobel算子可以直接去百度百科:百度百科
这里有些斜着拍的照片用sobel定位很失败,可以考虑颜色定位,车牌的颜色一般为黄色或者蓝色。
我们利用sobel算子计算出图片中的垂直边缘。
这里有些图片有很多干扰,比如奥迪车,迈腾车,车的前大灯。
openCV中的sobel函数。
二值化
我们将上一步得到的灰度化图片做二值化处理。之前的灰度化图片的取值是0~255,代表灰暗程度,现在设定一个阀值,大于某个值那么设为1,否则为0,这样就得到了一个二值化的图片。
这一步是为了后续闭操作或者其他算子做准备。
threshold(src, dest, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
闭操作
闭操作讲解,包含腐蚀、膨胀等:闭操作
闭操作就是对图像先膨胀,再腐蚀。闭操作的结果一般是可以将许多靠近的图块相连称为一个无突起的连通域。在我们的图像定位中,使用了闭操作去连接所有的字符小图块,然后形成一个车牌的大致轮廓。
可能存在因为车牌中字母相隔太远造成闭操作后车牌分成两块。
morphologyEx(img_threshold, img_threshold, MORPH_CLOSE, element);
取轮廓
闭操作后取出矩形框轮廓。
vector< vector< Point> > contours;
findContours(img_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL, // 提取外部轮廓
CV_CHAIN_APPROX_NONE); // all pixels of each contours
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示。
形态学操作
中国车牌的一般大小是440mm*140mm,面积为440*140,宽高比为3.14
- 尺寸判断:看取出的轮廓是否和车牌符合,先筛选一遍可能的车牌
- 角度判断:进一步筛选。比如前大灯的角度显然不符合车牌角度
- 旋转操作:将偏斜的车牌跳转为水平。
- 大小调整:设定一个图片大小,用openCV中的resize函数。
通过对图像中所有的轮廓的外接矩形进行遍历,我们调用CplateLocate的另一个成员方法verifySizes,代码如下:
//! 对minAreaRect获得的最小外接矩形,用纵横比进行判断
bool CPlateLocate::verifySizes(RotatedRect mr)
{
float error = m_error;
//Spain car plate size: 52x11 aspect 4,7272
//China car plate size: 440mm*140mm,aspect 3.142857
float aspect = m_aspect;
//Set a min and max area. All other patchs are discarded
//int min= 1*aspect*1; // minimum area
//int max= 2000*aspect*2000; // maximum area
int min= 44*14*m_verifyMin; // minimum area
int max= 44*14*m_verifyMax; // maximum area
//Get only patchs that match to a respect ratio.
float rmin= aspect-aspect*error;
float rmax= aspect+aspect*error;
int area= mr.size.height * mr.size.width;
float r = (float)mr.size.width / (float)mr.size.height;
if(r < 1)
{
r= (float)mr.size.height / (float)mr.size.width;
}
if(( area < min || area > max ) || ( r < rmin || r > rmax ))
{
return false;
}
else
{
return true;
}
}
2. SVM训练筛选车牌
经过以上操作后得到了可能是车牌的标准矩形框,之后再用SVM来区分。
SVM应用
svm是类CvSVM的一个对象。这个类是opencv里内置的一个机器学习类。在这里我们主要用来做二分类。
训练和预测两个过程是分开的。也就是说你们在使用EasyPR时用到的CvSVM类是我在先前就训练好的。我是如何把我训练好的模型交给各位使用的呢?CvSVM类有个方法,把训练好的结果以xml文件的形式存储,我就是把这个xml文件随EasyPR发布,并让程序在执行前先加载好这个xml。这个xml的位置就是在文件夹Model下面–svm.xml文件。
SVM训练
详见开发地址。
SVM调优
注意
Mat是OpenCV最基本的数据结构,Mat即矩阵(Matrix)的缩写,Mat数据结构主要包含2部分:Header和Pointer。Header中主要包含矩阵的大小,存储方式,存储地址等信息;Pointer中存储指向像素值的指针。我们在读取图片的时候就是将图片定义为Mat类型,其重载的构造函数一大堆。
当你的数据量很大,但是每个数据量的维度一般时,才适合用rbf核。相反,当你的数据量不多,但是每个数据量的维数都很大时,适合用线型核。
二、字符识别
这个过程承接上一个车牌定位过程,由得到的车牌分析出里面的车牌号。
这个大过程也主要分成两个小的过程,一个是切割字符:把一个整体的车牌按照字符切割开。然后逐个辨别每个字符。
由于在车牌定位中,我们使用了归一化过程。因此所需要处理的车牌的大小是统一的,在目前的版本中(v1.3),这个值是136*36。
1. 切割字符
灰度化
首先,我们把彩色的图片转化为灰度化图片。注意:为了以后可以利用彩色信息,在前面的车牌检测过程中,我们的输出结果不是灰度化图片,而是彩色图片。
灰度化的过程与上述过程一致。
颜色定位
颜色定位是为了后面二值化,后面的二值化根据不同颜色设定阀值。
明确了使用HSV模型以及用阈值进行判断以后,下面就是一个颜色定位的完整过程。
- 第一步,将图像的颜色空间从RGB转为HSV,在这里由于光照的影响,对于图像使用直方图均衡进行预处理;
- 第二步,依次遍历图像的所有像素,当H值落在200-280之间并且S值与V值也落在0.35-1.0之间,标记为白色像素,否则为黑色像素;
取轮廓
利用函数findcontours。
注意:直接使用findContours方法取轮廓时,在处理中文字符,也就是“苏”时,会发生断裂现象。因此这里可以采用外接矩形法。
可以先确定后面的所有数字和字母,最后确定第一个中文字符,可以根据宽度截取该中文字符的外接矩形。
2. ANN训练
这个步骤就是训练ANN,然后输入分割后的字符块,就能得到相应的字符。就类似于手写识别。