author:zox
实验环境:Matlab2019a
课程设计:汽车车牌识别
序号 | 内容 |
---|---|
0 | [任务+原理+设计方案] |
1 | 车牌图像预处理 |
2 | 车牌定位 |
3 | 车牌字符分割 |
4+5 | 车牌字符识别+结果分析 |
6 | 总结 |
∞ | 源代码 |
三、课程设计步骤和结果
3.车牌字符分割
由于图像车牌区域提取后获得的是从原始图像中剪切的,是 RGB图像,字符分割采取投影法,故同样需要先将 RGB图像转换成灰度值再将灰度图转化成二进制图。
接着根据投影法对图像水平和垂直投影数据分别进行峰谷分析,得到各个字符的中心位置,以及字符的最大高度和最大宽度,接下来就可根据这些信息对二值化的车牌区域图像进行分割,得到车牌上的字符。
对于字符分割部分我们得到了一些图像数据,其对应索引表如下:
表-3 字符分割图像索引
图像名称 | 图像注解 |
---|---|
License | 定位到的车牌区域彩色图像 |
J1 | 灰度化处理后的灰度图像 |
J2 | 二值化处理后的二值图像 |
J3 | 实施开运算后的图像 |
J4 | 根据字符和底色的面积比例膨胀或腐蚀后的图像 |
J5 | 消除小对象后的图像 |
J6 | 去掉水平边框后的图像 |
hiscol | 车牌二值图像对应的垂直投影数据 |
hisrow | 车牌二值图像对应的水平投影数据 |
J7 | 切割得到的车牌字符图像 |
J8 | 标准化大小为40×20的车牌字符图像 |
3.1字符分割前的预处理
字符分割前对图像的预处理不仅仅是简单地将图像灰度化,二值化,由于车牌中除了7个字符之外,还有第2和第3个字符之间的圆点、车牌定位不准确导致的车牌边框轮廓、固定车牌的螺丝钉等信息,并且对于一些车牌图像还会有噪声会对之后的字符分割造成影响,导致分割不准确,所以在字符分割前要进行一系列的操作。具体的流程图如下:
首先和前面预处理时一样要对车牌图像进行统一高度的处理,这样方便于后面消除小对象。因为车牌的尺寸为440×140,为了便于操作,我们选择70为统一的高度,按照比例,如果前面对于图像的定位较准确的话,图像的宽度就在220左右。
然后再使用自编写的myrgb2gray将彩色图像灰度化,自编写的myim2bw函数使用最大类间差法选取合适的阈值对图像实施二值化操作,得到的图像如下图所示:
此时得到的二值图像效果已经很明显,得到了车牌的7个字符,很明显字符的边缘有很多的毛刺、还有一些边界的噪声点需要处理。
所以接下来先对图像实施开运算操作,开运算是对图像先腐蚀操作,能够去除孤立的小点、毛刺和小桥、消除小物体、平滑较大物体的边界, 再膨胀操作不明显改变其面积。这里选择的结构元素为:
m o d e l = [ 0 1 0 1 1 1 0 1 0 ] \ \ model=\left[\begin{matrix}0&1&0\\1&1&1\\0&1&0\\\end{matrix}\right]\ \ \ \ \ model=⎣⎡010111010⎦⎤
由此实施开运算得到的图像为:
观察开运算后的图像看到每个字符的边缘已经平滑了许多。
再根据经验值,车牌图像中,字符面积与车牌面积之比在 (0.235,0.365)之间,因此使用bwarea函数来计算字符面积与车牌面积比值,如果大于0.365则对图像进行腐蚀,如果小于0.235则对图像进行膨胀,否则不做处理。这里选择的结构元素为:
m o d e l = [ 0 0 0 0 1 0 0 0 1 ] model=\left[\begin{matrix}0&0&0\\0&1&0\\0&0&1\\\end{matrix}\right] model=⎣⎡000010001⎦⎤
由此实施腐蚀或膨胀操作后得到的图像为:
最后要消除车牌二值图像中的细小对象,主要是还有第2和第3个字符之间的圆点,在之后投影法对字符分割的时候会有影响,所以需要消除,这里仍采用自编写的mycut函数,在多次测试中选取合适的P的值为50,即消除连通区域面积小于50的部分,得到新的车牌区域二值化图像如下:
3.2投影法字符分割
字符分割的任务很显然就是把单个字符从车牌字符串中分离出来,所以采用投影法根据车牌特征信息排除以下干扰,实施字符分割:
1)排除尺寸大小或长宽比例不符合车牌字符特征的连通域,滤除大部分噪声点的干扰;
2)确定车牌字符精确的起始行与结束行位置,排除螺钉对第二和第六个字符的干扰;
3)充分利用车牌字符的位置和顺序信息,查找连通域漏检的字符,排除干扰区域。
总的来讲,就是对车牌图像水平投影和垂直投影结合对图像的数据信息进行分析,字符分割的流程图如下:
在投影过程中有一些关键的变量信息注解如下:
表-4 投影法变量索引表
变量名称 | 变量注解 |
---|---|
markrow | markcol | 峰上升点的位置 |
markrow1 | markcol1 | 下降点到下一个上升点之间的谷底宽度 |
markrow2 | markcol2 | 上升点到下一个上升点的两个峰的峰距 |
markrow3 | markcol3 | 峰下降点的位置 |
markrow4 | markcol4 | 上升点到下降点之间的峰宽度 |
markrow5 | markcol5 | 每个峰的中心位置(即字符中心位置) |
markcol6 | 每两个字符中心的距离 |
maxhight | maxwidth | 最大字符高度 | 最大字符分割宽度 |
首先第一步我们根据车牌的二值图像计算出水平投影和垂直投影的数据为hiscol和hisrow,并使用bar函数来绘制直方图如下:
第二步则是先对图像的水平投影进行峰谷分析,很明显从二值图像和水平投影图中都可以很直观的看出来车牌除字符区域外的上下区域还是有部分留空,而且对于有些车牌图像还会有一些噪声的影响,所以在分割前需要将上下的水平边框给去掉,由此得到车牌字符的最大高度,这部分的关键代码如下:
%对水平投影进行峰谷分析:消除车牌上下边界的影响
levelrow=(mean(histrow)+min(histrow))/2;%把水平投影的均值和最小值的平均值作为阈值去判断是否为车牌区域
count1=0;%参数:统计谷底点的个数
mt=1;%参数:上升点个数
for k=1:hight %hight为车牌高
if histrow(k)<=levelrow %当水平投影的数据低于水平阈值,说明其是谷底
count1=count1+1; %统计谷底点的个数,用于计算字符高度
else %不是谷底
if count1>=1 %该点前是宽度为count1的谷底
markrow(mt)=k;%记录上升点(点的位置)字符区域
markrow1(mt)=count1;%记录谷宽度(谷点的数量,即下降点至下一个上升点)
mt=mt+1; %上升点个数加1
end
count1=0; %统计一个谷底,计数清零
end
end
if mt==2 %只有一个上升点(车牌区域的)
markrow(mt)=hight; %添加最后一个字符
markrow1(mt)=count1; %谷底点数
mt=mt+1;
end
markrow2=diff(markrow);%峰距数列(上升点至下一个上升点)
[~,n1]=size(markrow2); %m1=1,n1为总峰距数
n1=n1+1; %峰数n1=3
markrow(mt)=hight; %指最后一个字符
markrow1(mt)=count1; %谷底点数
for k=1:n1 %该循环用于找峰中心位置,即字符高度的中点
markrow3(k)=markrow(k+1)-markrow1(k+1);%上一个下降点
markrow4(k)=markrow3(k)-markrow(k);%峰宽度(上升点至下降点)
markrow5(k)=markrow3(k)-double(uint16(markrow4(k)/2));%峰中心位置
end
%去水平(上下)边框,获取字符高度
maxhight=max(markrow2);%获取最大峰距,即一个字符+一个谷底宽
findrow=find(markrow2==maxhight);%返回的是最大峰距所在序数
rowtop=markrow(findrow);%最大峰距的上升点位置
rowbot=markrow(findrow+1)-markrow1(findrow+1);%最大峰距的下一个上升点-最大峰距所在的谷底度=最大字符宽度下降点
J6=J5(rowtop:rowbot,:); %去掉水平边框后
maxhight=rowbot-rowtop+1; %最大字符高度(rowbot-rowtop+1)
由此对原车牌的二值图像先去掉水平边框,由此得到新的车牌图像以及对应的垂直投影数据如下图所示:
第三步就是对图像的垂直投影数据进行峰谷分析,具体的还是和水平投影的分析步骤相同,但我们可以很明显的从垂直投影图中看到除了7个字符所在的峰之外,还有车牌左边界的峰会造成影响,而实际情况中有时候会有左右边界,有时会只有左边界、只有右边界,甚至还有可能会没有。
所以为了统一对这些情况都处理到,我们在原来代码的基础上添加如下代码来直接赋值,增加左右边界所在的峰数据,左边界为0,右边界为图像的宽度。这样不管是任何一张车牌的图像都能够有9个峰,那接下来数据的处理就比较方便了。
if mt==7 %没有左右边界
while mt>1 %交换位置
markcol(mt)=markcol(mt-1); %字符上升点
markcol1(mt)=markcol1(mt-1); %谷宽度
mt=mt-1;
end
markcol(1)=0; %添加左边界
markcol1(1)=0;
mt=8;
end
if mt==8 %没有右边界
markcol(mt)=width;%把最后一个上升点设为车牌宽度右边界所在点
markcol1(mt)=count1;%最后谷底宽度
markcol2(mt)=markcol(mt)-markcol(mt-1);
mt=mt+1;
end
另外在车牌字符中,字符的宽度是不确定的。如字符“1” 和“0” ,但字符的高度均相同。因此,在垂直投影分析时根据字符中心位置的距离来得到字符分割的最大宽度。而在前面对车牌图像的预处理中消除了第2、第3字符之间的圆点,所以通常情况下字符中心距离最大的就是第2、第3字符间的距离,由此可确定字符分割是从什么位置开始。
最后第四步就是根据水平投影和垂直投影得到的一些字符的有效信息来对字符进行分割,并将它们保存在文件的子目录下,方便之后对字符的识别。