MATLAB汽车号码识别系统设计

汽车号牌识别系统设计

中文摘要:随着二十一世纪到来,经济快速发展和人们生活水平显著提高,汽车逐渐成为家庭的主要交通工具。汽车的产量快速增多,车辆流动也变得越来越频繁,因此给交通带来了严重问题,如交通堵塞、交通事故等,智能交通系统(Intelligent Transportation System)的产生就是为了从根本上解决交通问题。在智能交通系统中车牌识别技术占有重要位置,车牌识别技术的推广普及必将对加强道路管理、城市交通事故、违章停车、处理车辆被盗案件、保障社会稳定等方面产生重大而深远的影响。

该设计主要研究基于MATLAB软件的汽车号牌设别系统设计,系统主要包括图像采集、图像预处理、车牌定位、字符分割、字符识别五大核心部分。系统的图像预处理模块是将图像经过图像灰度化、图像增强、边缘提取、二值化等操作,转换成便于车牌定位的二值化图像;利用车牌的边缘、形状等特征,再结合Roberts 算子边缘检测、数字图像、形态学等技术对车牌进行定位;字符的分割采用的方法是将二值化后的车牌部分进行寻找连续有文字的块,若长度大于设定的阈值则切割,从而完成字符的分割;字符识别运用模板匹配算法完成。以上每个功能模块用MATLAB软件实现,最后识别出车牌,在研究设计的同时对其中出现的问题进行具体分析、处理,并寻求更优的方法。


关键词:MATLAB,车牌识别系统,字符识别,图像处理


一、总体设计

汽车号牌识别系统技术是从一幅车辆图像中准确定位出车牌区域,然后经过字符切割和字符识别来实现车辆牌照的自动识别。主要流程图如下:

图1.1

二、总体功能模块

基于MATLAB车牌识别系统主要包括图像采集、图像预处理、车牌定位、字符分割、字符识别五个关键环节[11],其基本工作如下:

(1) 图像采集:使用摄像头、照相机拍摄采集图像。

(2) 图像预处理:把图像转换成便于定位的二值化图像,需要经过图像灰度化、图像

增强、边缘提取、二值化操作。

  1. 车牌定位:利用车牌的边缘、形状等特征,再结合Roberts 算子边缘检测、数字

图像、形态学等技术对车牌进行定位。

2字符分割:以二值化后的车牌部分进行寻找连续有文字的块,若长度大于设定的

阈值则切割,从而完成字符的分割。

3.字符识别:运用模板匹配算法将分割后的字符二值化,并将其尺寸大小缩放为模

板库中字符的大小,然后与所有的模板进行匹配,准确地识别车牌。输出识别

结果,并进行数据存储。

由于纹理特征车牌灰度图像的边缘、图像水平方向上的方差、水平方向上的梯度等比较稳定而且易于提取,所以本系统车牌定位算法采用纹理特征作为车牌的主要特征。在汽车号牌字符识别中,由于汉字的复杂性所以本设计的模板库字符包含5个汉字,26个大写英文字母及10个阿拉伯数字。首字符为汉字,第2-6个字符为英文字母或数字。本系统采用的是边缘检测的方法实现车牌定位的,寻找连续有文字的块的方法实现字符分割,模板匹配法来确定最终的识别结果。

三、具体设计

下图3.1流程图简要的概述了基本步骤:

v2-33d602b547784985482b03163a3a189d_b.jpg


图3.1


v2-8a51bc18c5e3f1dd82c293cf24487748_b.jpg


图3.2



v2-1e50ad7ac12bad307877f982428523f4_b.jpg


图3.3



v2-e7d9bcbc0370b91f5c8d2d15d3f8ba99_b.jpg


图3.4

v2-8f99106827b94b9ee13c2eec35b5ad9a_b.jpg

图3.5

v2-8751f65d8f1215316b69e89ab36b7df7_b.jpg

图3.6

v2-0ff4838cedcb62cc01f7aff2dc2ccb3f_b.jpg

图3.7

v2-6b351ec7d19aea84882baee4afcbf529_b.jpg

图3.8

v2-fad60f3e35b50264b9301577ddb8f726_b.jpg


图3.9


v2-25baaa7237137860223185d58f54728a_b.jpg


图3.10

由于本系统设计只限用于车牌底色为蓝色的车牌,对于其他颜色如黄色、白色等为底色的车牌则不成功。所以本系统具有一定的局限性。下面是分割后的车牌图:

v2-ae5cb8c0267533bc9d2a206cd9124561_b.jpg


图3.11


v2-8b5e019a1f75cacaa45f30a7487b86c5_b.jpg


图3.12

下图是字符的分割与归一化的流程图:

图3.13

本系统设计采用的方法是寻找连续有文字的块,若长度大于设定的阈值,则认为该块有两个字符组成,需要分割。

v2-88d959b1d1e20c196cc4f25535a9a555_b.jpg


图3.14

分割出来的字符可能存在一定的大小差距,所以要进行进一步的处理,以便接下来的字符识别能准确的识别出字符。本系统设计对分割出来的字符进行了归一化处理,归一化切割出来的字符图像的大小为40*20,与模板中字符图像的大小相匹配。

v2-03899d96fba2515816013fb294388fdb_b.jpg


图3.15

本系统的模板匹配的字符识别基本过程是:首先对待识别字符进行二值化并将其尺寸大小缩放为字符数据库中模板的大小,然后与所有的模板进行匹配,最后选最佳匹配作为结果。模板匹配的主要特点是实现简单,当字符较规整时对字符图像的缺损、污迹干扰适应力强且识别率相当高。流程图如下:


图3.16

本系统设计采用相减的方法找到出分割字符与模板库中的字符相似度最大的字符,然后输出。汽车号牌的字符一般有七个,大部分车牌第一位是汉字,通常代表车辆所属省份,接着的是字母与数字。车牌字符汉字共约50多个,大写英文字母26个,数字10个。为了提高系统的识别率与实验的方便,本次系统设计只建立了5个汉字26个字母与10个数字的字符模板库。

首先取模板库的字符,接着依次取待识别字符与模板进行匹配,将其与模板库字符相减,得到的0越多那么匹配成功率越高。把每一幅相减后的图的0值个数保存,即为识别出来的结果并将结果保存在Data.xls文件中。字符识别图如下:


v2-b4b248a23dc37b46f2557503c0c5d59c_b.jpg


图3.17

  1. 优化后实现

v2-b905e690730a324c84f6fb0c9ac359b1_b.jpg

图3.18

v2-03a6a897de9244aea9848890837843e6_b.jpg


图3.19

  1. 分析总结

汽车号牌识别系统是一个复杂的系统,考虑到时间和本人能力等因素,在这里我只做了一些初步的研究,很不够完善的地方,还需进一步的研究改进。

(1)汽车号牌识别系统是针对车牌为蓝底白字,7个字符水平排列的汽车车牌进行研

究。有些光照条件不理想的图片,需要先进行图象增强处理,让图象灰度动态范

围扩展和对比度增强,再进行车牌定位和分割,这样可以提高分割的成功率。色

彩通道的车牌区域分割算法充分利用了车牌图象的色彩信息,简化了算法的实现,

加快了图象的处理速度,具有较高的正确率,而且整个程序用MATLAB语言编

程实现,运算速度快。但是也存在一些识别效果不是很理想的图片,这些图片需

要做一些前提工作后才能识别出相应的字符。

(2)车牌定位和分割中利用的车牌区域的宽度信息以及字符尺寸信息,是根据采集到

的车辆图像通过人工或者经验测算出来的,实际中需要自动检测;

(3)由于基于寻找连续有文字的块的字符分割方法容易受噪声和环境光线变化的影

响,所以在车牌字符分割的预处理中,需要对分割出的字符车牌进行均值滤波,

膨胀或腐蚀的处理。经过这些处理可以把字符与字符之间的杂色点去除,只有白

色的字符和黑色的背景存在,有利于的字符分割进行[19]。

(4)字符识别方法中运用模板匹配的方法,方法简洁但识别率较低。模板匹配法,是

利用要识别的字符图片与字符库中的图片进行两幅图片相减的方法,找到相减后

值最小的图片,其相似程度最大的。模板库的字符制作很重要,必须要用精确的

模板,否则就不能正确的识别。

改进方法:

(1)在现有的基础上利用水平投影的方法检测非横向排列的7个字符车牌,根据车牌在水平方向上的投影的峰值特征判断牌照所属类型。

(2)在已定位车牌基础上检测牌照字符笔画的宽度,通过投影检测字符的尺寸信息;也可以通过摄像机架设的高度、角度与车道的关系,将这些参数作为系统参数进。

(3)改进字符分割的算法,在车牌定位以后对图像进行去噪处理,或者可以通过照明设备照射车辆,由于车辆牌照区域的反光特性,可以大大改善图像采集的质量,同时突出牌照区域,间接达到减少噪声的效果。

(4)可以考虑单独设备汉字识别器以及数字字母合一的识别来提高识别器的识别率!

附录:程序清单


1、车牌分割程序:

function [PY2,PY1,PX2,PX1]=chepai_fenge(I5)
[y,x,z]=size(I5);
myI=double(I5);
tic
Y_threshlow=5; %这个数值很重要。决定了提取的彩图的质量
X_firrectify=5;
%====================== Y 方向============================
Blue_y=zeros(y,1);
for i=1:y
    for j=1:x
        if(myI(i,j,1)==1)
           Blue_y(i,1)= Blue_y(i,1)+1;     % 蓝色象素点统计                    
        end  
    end       
end
        [temp MaxY]=max(Blue_y);% Y方向车牌区域确定 temp(最多点数):所有行中,最多的累积像素点 MaxY(最多点所在行):该行中蓝点最多
         PY1=MaxY;%有最多蓝点的行付给PY1
        while ((Blue_y(PY1,1)>=Y_threshlow)&&(PY1>1))%找到图片上边界
            PY1=PY1-1;
        end
        PY2=MaxY; %PY1:存储车牌上边界值
        while ((Blue_y(PY2,1)>=Y_threshlow)&&(PY2<y))%阈值为5
             PY2=PY2+1;
        end
       PY1, PY2 
    figure(1),imshow(Blue_y),title('y方向确定');
    pause(2);
    %==============X 方向===============================
        X_threshhigh=(PY2-PY1)/11;%这个数值很重要。决定了提取的彩图的质量,适当提高可抗干扰,但是小图会照成剪裁太多
        Blue_x=zeros(1,x);             % 进一步确定X方向的车牌区域
        for j=1:x
            for i=PY1:PY2
                if(myI(i,j,1)==1)
                 Blue_x(1,j)= Blue_x(1,j)+1;               
                end  
            end       
        end
        [temp MaxX]=max(Blue_x);
        PX1=MaxX-6*(PY2-PY1);
        if  PX1<=1
            PX1=1;
        end
        while ((Blue_x(1,PX1)<=X_threshhigh)&&(PX1<x))%阈值
              PX1=PX1+1;
        end               %确定出X方向车牌起点   
        PX2=MaxX+6*(PY2-PY1);
        if  PX2>=x
            PX2=x;
        end
        while ((Blue_x(1,PX2)<=X_threshhigh)&&(PX2>PX1))%阈值
               PX2=PX2-1;
        end            %确定出X方向车牌终点
        PX1 ,PX2
     figure(2),imshow(Blue_x),title('X方向确定'); 

2、车牌校正程序:

function [PY2,PY1,PX2,PX1,threshold]=chepai_xiuzheng(PY2,PY1,PX2,PX1)

S=(PY2-PY1)*(PX2-PX1)
if       S<=25000
    threshold=50;
    Y_secrectify=3;
    X_secrectify=3;
elseif S>25000&&S<=45000  
    threshold=100;
    Y_secrectify=-3;
    X_secrectify=3;
elseif S>45000&&S<=80000
    threshold=200;
    Y_secrectify=-3;
    X_secrectify=3;
elseif S>80000&&S<=150000
    threshold=300;
    Y_secrectify=-10;
    X_secrectify=-10;
elseif S>150000&&S<=400000
    threshold=600;
    Y_secrectify=-10;
    X_secrectify=-10;
else
    threshold=1800;
    Y_secrectify=-10;
    X_secrectify=-10;
end
PY1=PY1-Y_secrectify;
PY2=PY2+Y_secrectify;
PX1=PX1;
PX2=PX2;%对车牌区域的进一步修正
3、字符分割程序:
function e=zifufenge(d)
[m,n]=size(d);
top=1;bottom=m;left=1;right=n;
while sum(d(top,:))==0 && top<=m
    top=top+1;
end
while sum(d(bottom,:))==0 && bottom>=1
    bottom=bottom-1;
end
while sum(d(:,left))==0 && left<=n
    left=left+1;
end
while sum(d(:,right))==0 && right>=1
    right=right-1;
end
dd=right-left;
hh=bottom-top;
e=imcrop(d,[left top dd hh]);

4、获取字符程序:

function [word,result]=getword(d)%获取字符
word=[];flag=0;y1=8;y2=0.5;
    while flag==0
        [m,n]=size(d);
        wide=0;
        while sum(d(:,wide+1))~=0 && wide<=n-2
            wide=wide+1;
        end
        temp=zifufenge(imcrop(d,[1 1 wide m]));
        [m1,n1]=size(temp);
        if wide<y1 && n1/m1>y2
            d(:,[1:wide])=0;
            if sum(sum(d))~=0
                d=zifufenge(d);  % 切割出最小范围
            else word=[];flag=1;
            end
        else
            word=zifufenge(imcrop(d,[1 1 wide m]));
            d(:,[1:wide])=0;
            if sum(sum(d))~=0;
                d=zifufenge(d);flag=1;
            else d=[];
            end
        end
    end
          result=d;



5、主函数程序代码:

function varargout = main(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @main_OpeningFcn, ...
                   'gui_OutputFcn',  @main_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
pause(1);
function main_OpeningFcn(hObject, eventdata, handles, varargin)
set(handles.process,'enable','on')
handles.output = hObject;
guidata(hObject, handles);
function varargout = main_OutputFcn(hObject, eventdata, handles) 
tic
varargout{1} = handles.output;
function pushbutton1_Callback(hObject, eventdata, handles)
[filename pathname]=uigetfile({'*.jpg';'*.bmp'}, 'File Selector');
I = imread([pathname '\' filename]);
handles.I = I;
guidata(hObject, handles);
axes(handles.axes1);
imshow(I);title('原始图片')
set(handles.process,'enable','on')
function process_Callback(hObject, eventdata, handles)
I = handles.I;
I1=rgb2gray(I);
guidata(hObject, handles);
axes(handles.axes2);
imshow(I1);title('灰度图');
axes(handles.axes3);
imhist(I1);title('灰度图直方图');
pause(2);
imshow(I2);title('robert算子边缘检测');
pause(2);
se=[1;1;1];
I3=imerode(I2,se);
guidata(hObject, handles);
axes(handles.axes3);
imshow(I3);title('腐蚀后图像');
pause(2);
se=strel('rectangle',[10,25]);
I4=imclose(I3,se);
guidata(hObject, handles);
axes(handles.axes2);
imshow(I4);title('平滑图像的轮廓');
pause(2);
I5=bwareaopen(I4,2000);
guidata(hObject, handles);
axes(handles.axes2);
imshow(I5);title('从对象中移除小对象');
pause(2);
[PY2,PY1,PX2,PX1]=chepai_fenge(I5);%调用分割车牌
global threshold;
[PY2,PY1,PX2,PX1,threshold]=chepai_xiuzheng(PY2,PY1,PX2,PX1);%调用车牌校正
IY=I(PY1:PY2,:,:);
Plate=I5(PY1:PY2,PX1:PX2);
 global dw;
 dw=Plate;
PX1=PX1-1;%对车牌区域的校正
 PX2=PX2+1;
  dw=I(PY1:PY2-8,PX1:PX2,:);
  axes(handles.axes2);
  imshow(dw),title('车牌区域的校正');
 pause(2);
 t=tic;
guidata(hObject, handles);
axes(handles.axes2);
imshow(IY),title('水平方向合理区域');
axes(handles.axes3);
imshow(dw),title('定位剪切后的彩色车牌图像');
pause(2);
imwrite(dw,'New number plate.jpg');
[filename,filepath]=uigetfile('New number plate.jpg','输入一个定位裁剪后的车牌图像');
jpg=strcat(filepath,filename);
a=imread('New number plate.jpg');
b=rgb2gray(a);
figure(3),subplot(3,2,1),imshow(b),title('车牌灰度图像');
g_max=double(max(max(b)));
g_min=double(min(min(b)));
T=round(g_max-(g_max-g_min)/2); %T 为二值化的阈值
[m,n]=size(b);
d=(double(b)>=T);  % d:二值图像
figure(3),subplot(3,2,2),imshow(d),title('车牌二值图像');
figure(3),subplot(3,2,3),imshow(d),title('均值滤波前');
pause(1);
h=fspecial('average',3);% 滤波
d=im2bw(round(filter2(h,d)));
figure(3),subplot(3,2,4),imshow(d),title('均值滤波后');
se=eye(2); % eye(n) returns the n-by-n identity matrix 单位矩阵
[m,n]=size(d);
if bwarea(d)/m/n>=0.365
    d=imerode(d,se);
elseif bwarea(d)/m/n<=0.235
    d=imdilate(d,se);
end
figure(3),subplot(3,2,5),imshow(d),title('膨胀或腐蚀处理后');
pause(2);
%寻找连续有文字的块,若长度大于某阈值,则认为该块有两个字符组成,需要分割
d=zifufenge(d);
[m,n]=size(d);
guidata(hObject, handles);
axes(handles.axes3);imshow(d);
k1=1;k2=1;s=sum(d);j=1;
while j~=n
    while s(j)==0
        j=j+1;
    end
    k1=j;
    while s(j)~=0 && j<=n-1
        j=j+1;
    end
    k2=j-1;
    if k2-k1>=round(n/6.5)
        [val,num]=min(sum(d(:,[k1+5:k2-5])));
        d(:,k1+num+5)=0  % 分割
    end
end
d=zifufenge(d); % 再分割
% 切割出 7 个字符
y1=10;y2=0.25;flag=0;word1=[];
while flag==0
    [m,n]=size(d);
    left=1;wide=0;
    while sum(d(:,wide+1))~=0
        wide=wide+1;
    end
	if wide<y1   %  认为是左侧干扰
	        d(:,[1:wide])=0;
        d=zifufenge(d);
    else
        temp=zifufenge(imcrop(d,[1 1 wide m]));
        [m,n]=size(temp);
        all=sum(sum(temp));
        two_thirds=sum(sum(temp([round(m/3):2*round(m/3)],:)));
        if two_thirds/all>y2
            flag=1;word1=temp;  
        end
        d(:,[1:wide])=0;
        d=zifufenge(d);
    end 
end
 [word2,d]=getword(d); % 分割出第二个字符
pause(1);
 [word3,d]=getword(d); 
pause(1);
 [word4,d]=getword(d); 
pause(1);
 [word5,d]=getword(d); 
pause(1);
 [word6,d]=getword(d); 
pause(1);
 [word7,d]=getword(d); % 分割出第七个字符
pause(1);
guidata(hObject, handles);
axes(handles.axes4);imshow(word1),title('1');
guidata(hObject, handles);
axes(handles.axes4);imshow(word2),title('2');
guidata(hObject, handles);
axes(handles.axes4);imshow(word3),title('3');
guidata(hObject, handles);
axes(handles.axes4);imshow(word4),title('4');
guidata(hObject, handles);
axes(handles.axes4);imshow(word5),title('5');
guidata(hObject, handles);
axes(handles.axes4);imshow(word6),title('6');
guidata(hObject, handles);
axes(handles.axes4);imshow(word7),title('7');
[m,n]=size(word1);
word1=imresize(word1,[40 20]); % 商用系统程序中归一化大小为 40*20,此处演示
word2=imresize(word2,[40 20]);
word3=imresize(word3,[40 20]);
word4=imresize(word4,[40 20]);
word5=imresize(word5,[40 20]);
word6=imresize(word6,[40 20]);
word7=imresize(word7,[40 20]);
guidata(hObject, handles);
axes(handles.axes4);imshow(word1),title('1');
guidata(hObject, handles);
axes(handles.axes5);imshow(word2),title('2');
guidata(hObject, handles);
axes(handles.axes6);imshow(word3),title('3');
guidata(hObject, handles);
axes(handles.axes7);imshow(word4),title('4');
guidata(hObject, handles);
axes(handles.axes8);imshow(word5),title('5');
guidata(hObject, handles);
axes(handles.axes9);imshow(word6),title('6');
guidata(hObject, handles);
axes(handles.axes10);imshow(word7),title('7');
imwrite(word1,'1.jpg');
imwrite(word2,'2.jpg');
imwrite(word3,'3.jpg');
imwrite(word4,'4.jpg');
imwrite(word5,'5.jpg');
imwrite(word6,'6.jpg');
imwrite(word7,'7.jpg');
liccode=char(['0':'9' 'A':'Z' '桂鲁苏豫京']);  %建立自动识别字符代码表
SubBw2=zeros(40,20);
l=1;
for I=1:7
      ii=int2str(I);
     t=imread([ii,'.jpg']);
      SegBw2=imresize(t,[40 20],'nearest');
        if l==1                 %第一位汉字识别
            kmin=37;
            kmax=41;   
            pause(1);
        elseif l==2              %第二位 A~Z 字母识别
            kmin=11;
            kmax=36;   
            pause(1);
        else l>=3              %第三位以后是字母或数字识别
            kmin=1;
            kmax=36;       
        end     
        for k2=kmin:kmax
            fname=strcat('模板库\',liccode(k2),'.jpg');
            SamBw2 = imread(fname);
            for  i=1:40
                for j=1:20
                    SubBw2(i,j)=SegBw2(i,j)-SamBw2(i,j);
                end
            end    % 以上相当于两幅图相减得到第三幅图
            Dmax=0;
            for k1=1:40
                for l1=1:20
                    if  ( SubBw2(k1,l1) > 0 || SubBw2(k1,l1) <0 )
                        Dmax=Dmax+1;
                    end
                end
            end
            Error(k2)=Dmax;
        end
        Error1=Error(kmin:kmax);
        MinError=min(Error1);
        findc=find(Error1==MinError);
        Code(l*2-1)=liccode(findc(1)+kmin-1);
        Code(l*2)=' ';
        l=l+1;
end
guidata(hObject, handles);
axes(handles.axes3);imshow(dw),title(['车牌识别号码:', Code],'fontsize',25,'fontname','隶书');
pause(2);
fid = fopen('Data.xls', 'a+');
 fprintf(fid,'%s\r\n',Code,datestr(now));
 winopen('Data.xls');
 fclose(fid);
function pushbutton6_Callback(hObject, eventdata, handles)
close(gcf);

% --- 实现清屏功能.
function pushbutton7_Callback(hObject, eventdata, handles)
clc;
 cla(handles.axes1);
 cla(handles.axes2);
 cla(handles.axes3);
 cla(handles.axes4);
 cla(handles.axes5);
 cla(handles.axes6);
 cla(handles.axes7);
 cla(handles.axes8);
 cla(handles.axes9);
 cla(handles.axes10);

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值