实验
----用MATLAB实现车牌识别系统
--用MATLAB实现车牌识别系统
东南大学电子系 李浩翔 06006435
张雄
2010-1-10
索引:
实验目的
实验原理
实验步骤
1. 预处理
2. 边缘识别
3. 小区块联通
4. 车牌区域的识别并截取
5. 字符截取
6. 字符识别
实验思路
本程序的局限性
附录
附录1 程序源代码
1. 主程序
2. 子
数(code)
附录2 测试图像处理过程汇总
1. 测试图像1
2. 测试图像2
附录3 参考文献及参考程序
使用MATLAB对包含车牌的图片进行处理,利用算法识别出车牌所在的区域,并辨认()
其数字及字母,最后在屏幕上输出所识别出的车牌号。
()
1. 将拍摄下的彩色图像转换为灰度图,之后用中值滤波对灰度图像进行预处理,从而减少
干扰信息。
2. 使用sobel算子识别出图像的边缘,并转化为二值化图像。并对二值化之后的图像进行
卷积,加强边缘的轮廓。
3. 用膨胀-再腐蚀的
分别作用于图像的横轴与纵轴,将小块的联通区域连接起来,使
车牌的形状更加清晰,为下一步的识别做好准备。 4. 利用车牌长宽比的特性对各个联通区域进行判断,识别出车牌所在区域,并截取。
5. 对截取出的车牌区域进行进一步的处理,分割出各个字符。 6. 对分割出的字符进行特征判断,从而识别出具体的车牌号。
()
1. 预处理()
A. 将拍摄下的彩色图像转换为灰度图,便于进行接下来的算法处理。
im_gray=rgb2gray(im);
图1 拍摄下的图片
图2 转换的灰度图
B. 对灰度图进行中值滤波,减少干扰点对二值化运算结果的影响。
im_gray=medfilt2(im_gray,[3 3]);
图3 进行中值滤波后的灰度图
C. 将中值滤波后的灰度图用设定门限灰度的方法(取门限值为0.2)转化为二值化图像,
在后继的车牌区域截取运算中作为源图像使用。
Image = im2bw(im_gray, 0.2);
图4 使用设定灰度门限的方法获得的二值化图像 2. 边缘识别()
A. 利用sobel算子识别出图3中的边缘区域,并将其转换为二值化图像。在转换后的
二值化图像中,边缘区域被作为白点标出,而非边缘区域被黑色区域覆盖。
BW = edge(im_gray,'sobel');
图5 识别出的边缘区域
B. 使用卷积的方法,对图5的边缘区域进行加强,为下一步的运算做好准备。
msk=[0 0 0 0 0;
0 1 1 1 0;
0 1 1 1 0;
0 1 1 1 0;
0 0 0 0 0;];
B0=conv2(double(BW),double(msk));
图6 加强后的边缘区域
3. 小区块联通()
使用膨胀-再腐蚀的方法对图像进行三次处理,联通小区块,从而使车牌的形状更易于
识别。
A. 第一次处理,选用高为2宽为80的矩阵进行运算。
se=ones(2,80); B1=imdilate(B0,se); B2=imerode(B1,se);
图7 第一次膨胀运算后
图8 第一次腐蚀运算后 B. 第二次处理,选用高为20宽为2的矩阵进行运算。
se=ones(20,2);
B3=imdilate(B2,se);
B4=imerode(B3,se);
图9 第二次膨胀运算后
图10 第二次腐蚀运算后
C. 第三次处理,选用高为50宽为2的矩阵进行运算。
se=ones(50,2); B5=imdilate(B4,se); B6=imerode(B5,se);
图11 第三次膨胀运算后
图12 第三次腐蚀运算后
4. 车牌区域的识别与截取()
A. 以图12为目标图像进行联通区域的标记,并用线条给每个联通区域标上边界线。
[B,L] = bwboundaries(B6,4);
imshow(label2rgb(L, @jet, [.5 .5 .5])) %对联通区域进行标记
hold on
for k = 1:length(B) %用线条给联通区域标上边界线
boundary = B{k};
plot(boundary(:,2),boundary(:,1),'w','LineWidth',2)
end
图13 以图12为源图标记出联通区域
B. 单行的车牌号大多为长宽比为4.5:1的矩形(中外车牌皆如此,两行字的车牌除外)。以此为标准对各个联通区域进行判断,并以“metric”单元记录匹配度,匹配度
越接近1说明该联通区域越有可能是车牌。又由于车牌在图像中的面积不可能太小,因
此判定某联通区域为车牌的条件为:metric在0.85到0.15之间,且面积大于1000像素。
以图4为源文件截取出满足条件的联通区域,截取出的图像即为车牌区域。
stats = regionprops(L,'Area','Centroid'); % 找到每个连通域的质心
for k = 1:length(B) % 循环历遍每个连通域的边界
boundary = B{k}; % 获取一条边界上的所有点
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2))); % 计算边界周长
area = stats(k).Area; % 获取边界所围面积
metric = 27*area/perimeter^2; % 计算匹配度
metric_string = sprintf('%2.2f',metric); % 要显示的匹配度字串
if metric >= 0.85 && metric <= 1.15 && area >1000 % 截取出匹配度接近
1且面积大于1000像素的连通域
centroid = stats(k).Centroid;
plot(centroid(1),centroid(2),'ko'); % 提取该连通域所对应在二值图像中
的矩形区域
goalboundary = boundary;
s = min(goalboundary, [], 1);
e = max(goalboundary, [], 1);
goal = imcrop(Image,[s(2) s(1) e(2)-s(2) e(1)-s(1)]);
end
text(boundary(1,2)-35,boundary(1,1)+13,metric_string,'Color','g','FontSize',14,'F
ontWeight','bold'); % 显示匹配度字串
end
图14 标出匹配度后的联通区域
D. 对截取出的车牌图像进行反色处理,以便进行接下来的运算。
goal = ~goal; figure; imshow(goal);
图15 截取出的车牌区域 5. 字符截取()
A. 对截取出的车牌区域(图15)进行进一步的处理,将字符区域的上方区域以及下
方区域都从图像中舍弃。具体实现方法为:从该图的水平中轴开始向上扫描,扫描
到字符的顶端时(判断条件为该行白点数少于每行总点数的1/10)停止,并记录此
时的纵轴坐标;再从水平中轴向下扫描,扫描到字符的底端时停止,并记录此时的
纵轴坐标。之后,根据记录下的纵轴坐标对图15进行进一步的截取。
[a,b]=size(goal); for i= a/2:-1:1 %从图像水平中轴开始向上扫描,当白点数少于每行总点 数的1/10时,停止扫描,并将该行定义为车牌字符区域的上限. num=0; for j=1:b if goal(i,j)==1 num=num+1;
end end if num<(b*0.1) line_up=i; break; end end for i= a/2:a %从图像水平中轴开始向下扫描,当白点数少于每行总点数的 1/10时,停止扫描,并将该行定义为车牌字符区域的下限. num=0; for j=1:b if goal(i,j)==1 num=num+1; end end if num<(b*0.1) line_down=i; break; end end goal=goal(line_up:line_down,1:b); %根据之前定义的上下限截取车牌字符区 域
图16 舍弃字符上方以及下方后的车牌区域 B. 以图16为源图像进行字符分割。具体实现方法为:对图像进行列扫描,每当该列
的白点数从每列总点数的1/10以上掉落到每列总点数的1/10以下时,或者该列的
白点数从1/10以下上升到1/10以上时,记录该列。
[a,b]=size(goal);
row=zeros(18);
now=1;
flag=0;
for j=1:b %对截取出的字符区域进行竖列扫描,并取每列总点数的1/10作为
阈值点,当每列的白点数从阈值以上掉落到阈值以下或从阈值以下上升到阈值
以上时,记录该列的横坐标
num=0;
for i=1:a
if goal(i,j)==1
num=num+1;
end
end
if flag==0
if num<0.1*a
row(now)=j;
now=now+1;
flag=1;
end
else
if num>0.1*a
row(now)=j;
now=now+1;
flag=0;
end
end
end
C. 判断所记录下的第二列以及第三列之间的区域(即被列标记分割出的第三块区域)
是否含有有效字符,如含有有效字符,则从第三块区域开始扫描;如没有,则从第
二块区域进行扫描。判断是否为有效字符的依据为该区域宽度是否大于10。
if row(3)-row(2)>10
now=2;
else
now=1;
end
图17 字符分割示意图
图18 字符分割结果
D. 由标记部分(本步骤的B部分)可知,如某一块区域为字符区域,则其相邻区域
必为黑色区域,而与其相隔一块的区域必为字符区域。根据上一步的判断结果从第
二块或第三块区域开始,隔一块进行一次判断。如果该区域白点数大于总像素点的
2/5时,输出,且计数器l1加一(避免输出中国车牌所使用的点状分隔符)。对每
个字符区域调用子程序进行识别,如识别成功则将该字符的ASCII码记录在数组
中,且计数器l2加一。
图19 MATLAB界面的文件名输入及输出结果
6. 字符识别(子程序) ()
识别的具体过程如下:
A. 对截取的字符进行水平中轴的笔划扫描,并记录扫描到的笔画数,并记录为line_x。 B. 对截取的字符进行竖直中轴的笔划扫描,并记录扫描到的笔划数,并记录为line_y。 C. 对截取的字符进行白点总数的计算,如白点数大于字符总像素的4/5,则识别该字
符为“I”。
D. 对截取的字符下方的3/4处进行笔划扫描,并记录扫描到的笔划数,并记录为
line_x_1。
E. 对截取的字符下方的9/10处进行笔划扫描,并记录扫描到的笔划数,并记录为
line_x_2。
F. 对截取的字符的最左侧进行判断,如左数第一列的白点数大于每列总点数的4/5,
则记flag_1=1。
G. 对截取的字符的下方的9/10处进行点数计算,如该列的白点数大于每列总点数的
9/10,则记flag_2=1。
图20 扫描路线示意图
根据以上7个特征值,已可以识别出两幅测试图像中的“2”“4”“8”“9”“A”“B”“I”
“M”“P”等字符。具体程序请参见附录1。
()
1. 在最开始处理图像时,采用的是灰度门限法对图像进行二值化处理。但后来发现,
这种方法虽然很简单易行,但当车牌颜色变化时需要不断地改变门限阈值,且很容
易受噪声或背景图像中的干扰信息的影响。最后,在参阅了相关文献之后,使用边
缘识别+膨胀连接的方法,获得了较好的效果,且这种方法不受车牌颜色的限制,
当车牌字体变化时,只需在识别时进行反色处理即可。 2. 对车牌区域的识别采取的是对联通区域的周长面积比进行判断的方法。此方法易受
小区块联通区域的干扰,但可通过对联通区域的像素面积进行判断的方法进行缓
解。
3. 对字符的识别采取的是行列扫描+特征判断的方法。虽然本程序中并未对所有可能
出现的字符进行判断,但显而易见的是,通过足够多次的行列扫描,可识别出绝大
多数字符。对于一些行列扫描难以判断的字符,则可通过一些字符的固有特征来判
断。比如在传统方法(傅里叶变换识别字符匹配)中难以区分的“8”和“B”,即
可以通过扫描它们的最左侧一列进行判断,如果扫描到竖线则为“B”,反之则为
“8”。
()
1. 本程序并未对车牌的倾斜程度进行判断,所以只适用于识别较为水平的车牌。
2. 在对边缘区域进行膨胀处理时的参数为不断调试的结果,并不具有普适性。但这也
是由于平常拍摄的车牌照片的大小与背景均无特定规律所致。相信在当运用于固定
场合拍摄的的具有相对固定的大小的车牌照片时,此缺陷可通过调整合适的参数来
克服。
3. 由于时间以及图源所限,在字符判断时并没有识别所有的字符。在拥有足够的时间
以及图源时,此缺陷可以很快克服。
()
1 ()
()
clc;
clear all;
k=input('Enter the file name: ','s'); % 输入车牌照片 im=imread(k);
imshow(im);
im_gray=rgb2gray(im);
im_gray=medfilt2(im_gray,[3 3]); %对图像进行中值滤波 Image = im2bw(im_gray, 0.2);
BW = edge(im_gray,'sobel'); %找出图像边缘 [imx,imy]=size(BW); %计算图像大小
msk=[0 0 0 0 0;
0 1 1 1 0;
0 1 1 1 0;
0 1 1 1 0;
0 0 0 0 0;];
B0=conv2(double(BW),double(msk)); %对边缘区域进行加强
se=ones(2,80);
B1=imdilate(B0,se);
% imshow(B1);
B2=imerode(B1,se);
% figure; imshow(B2);
se=ones(20,2);
B3=imdilate(B2,se);
% figure; imshow(B3);
B4=imerode(B3,se);
% figure; imshow(B4);
se=ones(50,2);
B5=imdilate(B4,se);
% figure; imshow(B5);
B6=imerode(B5,se);
% figure; imshow(B6); %对边界图进行小区块联通,使车牌区域联通为一个方块
[B,L] = bwboundaries(B6,4);
imshow(label2rgb(L, @jet, [.5 .5 .5])) %对联通区域进行标记 hold on
for k = 1:length(B) %用线条给联通区域标上边界线
boundary = B{k};
plot(boundary(:,2),boundary(:,1),'w','LineWidth',2)
end
stats = regionprops(L,'Area','Centroid'); % 找到每个连通域的质心
for k = 1:length(B) % 循环历遍每个连通域的边界
boundary = B{k}; % 获取一条边界上的所有点
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2))); % 计算边界周长
area = stats(k).Area; % 获取边界所围面积
metric = 27*area/perimeter^2; % 计算匹配度
metric_string = sprintf('%2.2f',metric); % 要显示的匹配度字串
if metric >= 0.85 && metric <= 1.15 && area >1000 % 截取出匹配度接近1且面积大
于1000像素的连通域
centroid = stats(k).Centroid;
plot(centroid(1),centroid(2),'ko'); % 提取该连通域所对应在二值图像中的矩形区域
goalboundary = boundary;
s = min(goalboundary, [], 1);
e = max(goalboundary, [], 1);
goal = imcrop(Image,[s(2) s(1) e(2)-s(2) e(1)-s(1)]);
end
text(boundary(1,2)-35,boundary(1,1)+13,metric_string,'Color','g','FontSize',14,'FontWeight','b
old'); % 显示匹配度字串
end
goal = ~goal; %对截取图像进行反色处理 figure;
imshow(goal);
[a,b]=size(goal);
for i= a/2:-1:1 %从图像水平中轴开始向上扫描,当白点数少于每行总点数的1/10时,停
止扫描,并将该行定义为车牌字符区域的上限.
num=0;
for j=1:b
if goal(i,j)==1
num=num+1;
end
end
if num<(b*0.1)
line_up=i;
break;
end
end
for i= a/2:a %从图像水平中轴开始向下扫描,当白点数少于每行总点数的1/10时,停止
扫描,并将该行定义为车牌字符区域的下限.
num=0;
for j=1:b
if goal(i,j)==1
num=num+1;
end
end
if num<(b*0.1)
line_down=i;
break;
end
end
goal=goal(line_up:line_down,1:b); %根据之前定义的上下限截取车牌字符区域
figure; imshow(goal); %显示车牌字符区域
[a,b]=size(goal);
row=zeros(18);
now=1;
flag=0;
for j=1:b %对截取出的字符区域进行竖列扫描,并取每列总点数的1/10作为阈值点,当
每列的白点数从阈值以上掉落到阈值以下或从阈值以下上升到阈值以上时,记录该列的
横坐标
num=0;
for i=1:a
if goal(i,j)==1
num=num+1;
end
end
if flag==0
if num<0.1*a
row(now)=j;
now=now+1;
flag=1;
end
else
if num>0.1*a
row(now)=j;
now=now+1;
flag=0;
end
end
end
if row(3)-row(2)>10 %判断扫描出的第二块区域(扫描到的第二列与第三列之间)是否包
含有效字符.如包含,则将扫描到的第二列定为字符分割的起始列;否则,则定义第一列为
起始列.
now=2;
else
now=1;
end
figure;
l1=0;
l2=0;
for k=1:8
m=row(now);
n=row(now+1);
temp=goal(1:a,m:n);
point=0; % 扫描每一个字符图片的白点点数
for i=1:a
for j=1:n-m
if temp(i,j)==1
point=point+1;
end
end
end
if point>0.4*a*(n-m) && n>m % 当扫描到的白点数小于总点数的2/5时放弃输出
(有可能是车牌上的点状分隔符);
l2=l2+1; % l2用来记录识别出的字符数
subplot(1,7,l2);
x(k)=code(temp); % 调用子程序进行字符扫描,并返回字符的ASCII码.
x(k)=uint8(x(k));
if x(k)>0 % 当所选区域不为空时进行输出.
l1=l1+1; %l1用来记录输出的字符数
s(l1)=char(x(k));
end
temp(32,32)=0;
imshow(temp);
end
now=now+2;
end
y=char(s); % 将得到的ASCII码重新转换为字符并在屏幕上输出
fprintf('\r\n该车辆的车牌号为: \r\n');
disp(y);
fprintf('\r\n输出的字符数为: %4d\r\n',l1);
fprintf('识别出的字符数为: %4d\r\n',l2);
code()
function co=code(aim)
[a1,b1]=size(aim);
num1=0;
for i1=1:a1
for j1=1:b1
if aim(i1,j1)==1
num1=num1+1;
end
end
end
ch=0;
if num1>a1*b1*0.8
ch='I';
end
line_x=0;
line_y=0;
flag=0;
for i1=1:a1
if aim(i1,round(b1/2))==1 && flag==0
flag=1;
line_y=line_y+1;
end
if aim(i1,round(b1/2))==0 && flag==1
flag=0;
end
end
flag=0;
for j1=1:b1
if aim(round(a1/2),j1)==1 && flag==0
flag=1;
line_x=line_x+1;
end
if aim(round(a1/2),j1)==0 && flag==1
flag=0;
end
end
line_x_1=0;
flag=0;
for j1=1:b1
if aim(round(a1*3/4),j1)==1 && flag==0
flag=1;
line_x_1=line_x_1+1;
end
if aim(round(a1*3/4),j1)==0 && flag==1
flag=0;
end
end
line_x_2=0;
flag=0;
for j1=1:b1
if aim(round(a1*9/10),j1)==1 && flag==0
flag=1;
line_x_2=line_x_2+1;
end
if aim(round(a1*9/10),j1)==0 && flag==1
flag=0;
end
end
flag_1=0;
flag_2=0;
num1=0;
for j1=1:b1
if aim(round(0.9*a1),j1)==1
num1=num1+1;
end
end
if num1>b1*0.9
flag_2=1;
end
num1=0;
for i1=1:a1
if aim(i1,1)==1
num1=num1+1;
end
end
if num1>round(29*0.8)
flag_1=1;
end
if line_x==1 && line_y==3 && flag_2==1 && ch==0
ch='2';
end
if line_x==1 && line_y==3 && flag_1==1 && ch==0
ch='B';
end
if line_x==1 && line_y==3 && flag_1==0 && ch==0 && line_x_1==2
ch='8';
end
if line_x==1 && line_y==1 && ch==0
ch='M';
end
if line_x==2 && line_y==2 && flag_1==1 && ch==0
ch='P';
end
if line_x==2 && line_y==2 && flag_1==0 && ch==0 && line_x_1==2
ch='A';
end
if line_x==2 && line_y==2 && flag_1==0 && ch==0
ch='4';
end
if line_x==1 && line_y==3 && ch==0
ch='9';
end
co=ch-0;
2 ()
1()
1
2
3
4
5
6
7
8
9
10
11
12
13 12
14
15
16
17
18
19 MATLAB
20
() 2
1
2
3
4 -
5
6
7
8 MATLAB
3 ()
1. 车牌定位与字符分割算法研究与实现 王晓健 北京邮电大学硕士研究生毕业论文
2009.03.05
2. 一种改进的车牌字符分割算法及MATLAB实现 欧卫华 怀化学院 3. Matlab在图像处理与目标识别方面的应用实验 林健 北京理工大学计算机科学
技术学院