本文地址:http://blog.csdn.net/shanglianlm/article/details/78045170
本文主要处理汽车车牌的识别过程,包括三个步骤,一:车牌区域检测,本文利用车牌的颜色和形状特征确认并获取汽车的车牌位置,二:字符分割,将获取到的汽车车牌按不同字符进行切割,三:车牌识别,最后利用模板匹配方式对切割的字符进行识别达到最终的车牌识别。
二 字符分割
1 首先对输入的车牌二值化,阈值使用最大类间方差法获取
代码
thresh = graythresh(Img); %自动确定二值化阈值
bwImg = im2bw(Img,thresh); %对图像二值化
2 去除上下左右边框 下图是图像的X轴(图像行累加)和Y轴(图像列累加)以及去除边框的车牌区域。
直观上来说,图像的边框上的值(行累加或者列累加)比较大,因此我们可以用下面条件去去除边框
边框的切割点满足两个条件:
a 切割点一般是图像的极大值点;
b 切割点距离图像边缘不是很远,一般在1/10范围内。
我们根据上述两个条件很容易去掉图像的边框。
3 左右切割,下图是去除边框后X轴(图像行累加)以及最后的切割点(绿色圆圈标识):
1)我们先设定每个字符的最小宽度,最大宽度以及最小区域;
2)很明显字符的垂直分割线应该位于字符与字符的中间黑色区域,这些地方的行累加值要比字符上的行累加值要小,所以我们从底到上扫描,递归地找到一些可能的切割区域,递归满足以下条件:
a 每个字符的切割宽度要大于最小宽度,小于最大宽度;
b 当切割区域大于最大宽度时,证明该区域可能含有多个字符,要对该区域继续切割,直至满足条件a。
c 当切割区域小于最小宽度时,证明该区域不存在任何字符,切割无效,要去除该切割点。
3)获取到的切割区域可能会大于7个区域,所以我们从大于最小区域的切割区域中选择最大的7个输出。
代码
[cut_m,cut_n] = size(cut_bwImg);
cut_sumCol = sum(cut_bwImg,1);
cut_sumRow = sum(cut_bwImg,2);
%左右切割
minDigitWidth = 5;
maxDigitWidth = 25;
minColArea = 250;
col_intevl = 1;
offset = 1;
col_seg = findValleys(cut_sumCol, col_intevl, offset,minDigitWidth, maxDigitWidth);
col_seg= clean(col_seg,minDigitWidth);
result_seg_col = chooseBestSeg(col_seg,cut_sumCol,minColArea,7);
seg = result_seg_col;
4 上下切割,下图是去除边框后Y轴(图像列累加)以及最后的切割点(红色圆圈标识):
]
同上,这里我们只需要一个合适的输出即可。
代码
% 上下切割
minDigitHeight = 20;
maxDigitHeight = 50;
minRowArea = 150;
row_intevl = 1;
offset = 1;
row_seg = findValleys(cut_sumRow', row_intevl, offset,minDigitHeight, maxDigitHeight);
row_seg= clean(row_seg,minDigitHeight);
result_seg_row = chooseBestSeg(row_seg,cut_sumRow',minColArea,1);
new_bwImg = cut_bwImg(result_seg_row(1,1):result_seg_row(1,2),:);
5 最后切割
切割线示意图
切割出的字符
其他代码如下:
寻找合适切割点
function seg = findValleys(tem, val, offset,minDigitWidth, maxDigitWidth)
val = val+1;
seg = find(tem < val);
if(length(seg) < 2)
seg = findValleys(tem, val, offset,minDigitWidth, maxDigitWidth);
return;
end;
if length(seg) == 0
return;
end;
if((tem(1,1) >= val) && seg(1) ~= 1)
seg = [1 seg];
end;
if((tem(1, length(tem)) >= val) && seg(length(seg)) ~= length(tem))
seg = [seg length(tem)];
end;
seg = seg + (offset - 1);
seg = clean(seg, minDigitWidth);
seg_gap=diff(seg);
for j=1:length(seg_gap)
if seg_gap(1,j)>maxDigitWidth
new_tem = tem(1,seg(j)- offset + 1 :seg(j+1)- offset + 1 );
new_valleys = findValleys(new_tem,val,seg(j),minDigitWidth,maxDigitWidth);
seg = [seg(1:j) new_valleys seg(j+1:length(seg))];
end
end
end
去除较差的切割点
function t = clean(s, val)
t = [];
len = length(s);
i = 2;
j = 1;
while i <= len
while(s(i) - s(i-1) <= val)
i = i + 1;
if(i > len)
return;
end;
end;
if j == 1 || (s(i-1) - t(j-1)) > val
t(j) = s(i-1);
j = j + 1;
end;
t(j) = s(i);
j = j + 1;
i = i + 1;
end;
end
最后展示
figure(55),
subplot(331),imshow(Img);title('灰度图片');hold on;
subplot(332),imshow(bwImg);title('二值化');hold on;
subplot(334),plot(1:n,sumCol);title('X轴及其边框位置');hold on;
plot([cutColLeft cutColRight],sumCol([cutColLeft cutColRight]),'b+');hold on;
subplot(335),plot(1:m,sumRow);title('Y轴及其边框位置');hold on;
plot([cutRowTop cutRowBottom],sumRow([cutRowTop cutRowBottom]),'r+');hold on;
subplot(336),imshow(cut_bwImg);title('去除边框');hold on;
subplot(337),plot(1:cut_n,cut_sumCol);title('去除边框后X轴以及切割点');hold on;
plot(result_seg_col,cut_sumCol(result_seg_col),'go');hold on;
subplot(338),plot(1:cut_m,cut_sumRow);title('去除边框后Y轴以及切割点');hold on;
plot(result_seg_row,cut_sumRow(result_seg_row),'ro');hold on;
subplot(339),imshow(cut_bwImg);title('切割线');hold on;
plot([1:cut_n],result_seg_row(1,1),'r.',[1:cut_n],result_seg_row(1,2),'r.');hold on;
for i=1:size(result_seg_col,1)
plot(result_seg_col(i,1),[1:cut_m],'b.');hold on;
plot(result_seg_col(i,2),[1:cut_m],'b.');hold on;
end
cut_Img_new = [];
for i=1:size(result_seg_col,1)
cut_Img_new = [cut_Img_new cut_bwImg(result_seg_row(1,1):result_seg_row(1,2),result_seg_col(i,1):result_seg_col(i,2)) ones(result_seg_row(1,2)-result_seg_row(1,1)+1,1)];
end
subplot(333),imshow(cut_Img_new);title('切割出的字符');hold on;