车牌识别-基于模板匹配

基于模板匹配的车牌识别

  • 一、设计思路
  • 二、功能模块
    • 1、GUI界面创建
    • 2、图片选择
    • 3、车牌粗定位
    • 4、灰度化
    • 5、倾斜矫正
    • 6、二值化和第一次形态学处理
    • 7、精确定位
    • 8、第二次形态学处理
    • 9、字符分割
    • 10、归一化切割后的字符以及模板
    • 11、字符匹配
    • 12、语音播报
    • 13、退出系统和关于按钮
  • 三、总的操作图

一、设计思路

车牌识别程序的设计主要基于车牌的固有特点,这些特点指导算法的设计。在一个识别系统中首先选择某一个或几个车牌的特点,然后根据这些特点设计算法。一般情况下,选择的特点越多,识别的正确率越高,但程序也将变得冗杂,效率低下。因为本实验主要对小型汽车车牌识别系统的设计,所以总结小型汽车车牌的特点如下所示:
(1)颜色特点:车牌为蓝底白字。并且白色的面积占总面积的比例在一定范围之内。从这个特点中可以想到通过在一张照片中查找蓝色区域,并且区域内的白色面积占总面积的比例在一定范围内来初步定为车牌区域。
(2)形状特点:车牌形状为矩形,虽然图片中的车牌区域面积的大小不确定,但车牌区域的长与宽的比在一定范围之内,这一特点很容易通过编程语言实现。
(3)纹理特点:车牌信息是以水平方式排列的,所以水平方向的纹理特点是我们的主要研究方向。
(4)背景对比特点:车牌背景为蓝色,字符信息为白色。对车牌进行灰度化处理后,当从左向右扫描时,可以看到灰度值是有明显变化的。在字符与字符之间,有峰值和谷值。利用这个特点可以设计字符分割算法。
车牌识别-基于模板匹配_第1张图片
从图1中可以看出我国小型汽车车牌的特征。其中第一个字符为汉字,它是省、直辖市和自治区的简称。图2-1中的京即为北京的简称。第二个字符为该省、直辖市或自治区内的地级市、地区、自治州和盟的代码,其中‘A’表示省会、首府或直辖市中心。并且没有字母I和O。后面五位为车牌序号,序号为0到9,大于9用字母表示。
通过车牌的特点,车牌识别系统的主程序可分为GUI界面制作、图片选择、车牌定位、字符分割、字符识别、显示内容六个个大的部分。

二、功能模块

1、GUI界面创建

GUI(Graphical User Interfaces)中文名称为图形用户界面,是一种面向对象的设计,实现用户与计算机的交互。GUI模块是MATLAB的重要组成部分,因为在GUI设计时,MATLAB提供各种控件,比如菜单、文本框、按钮等,并且可以直接修改控件的属性,极大地方便编程。
GUI界面为一个图形界面,图形内有各种控件,对这些控件的操作是通过句柄(handle)完成,每个控件都有一个句柄,并且是唯一的。通过句柄选中对象,然后修改该对象的属性,完成对控件的精确控制。GUI给出很多控件,如图7-1所示,常用的控件有按钮、单选按钮、复选按钮、坐标轴、静态文本等等,每个控件都可编写回调函数,可以选择触发回调函数的条件,比如单击鼠标、选择菜单等等。
本文使用到GUI的控件有按钮、单选框、单选按钮、坐标轴框、静态文本、按钮组和面板。
车牌识别-基于模板匹配_第2张图片
车牌识别-基于模板匹配_第3张图片
在命令行窗口输入guide再按回车就可以打开设计GUI界面的窗口啦
在命令行窗口输入guide再按回车就可以打开设计GUI界面的窗口啦
然后根据自己的需要,将左侧控件拖到操作区部分,双击控件可以进入到控件的属性设置,可以设置颜色啊,文本啊,控件的ID啊之类的,然后鼠标右键→查看回调→选择回调函数然后就可以在代码编辑器里面在相应控件的回调函数写对应的操作代码。

2、图片选择

图片选择的操作代码写在“选择图片”按钮的回调函数内,通过uigetfile函数打开文件选择对话框,并返回文件的名称和路径,handles找到对应对象,guidata对更新后的结构体进行保存。之后的代码都是在“开始识别”按钮的回调函数里面了。

function varargout = xuliu_OutputFcn(hObject, eventdata, handles) 
varargout{1} = handles.output;
%点击‘选择图片’按钮执行的程序
function open_Callback(hObject, eventdata, handles)
[filename,pathname] = uigetfile('*.jpg','选择图片');
handles.filename = filename;
guidata(hObject,handles);
zhaopianlujing=[pathname filename];
handles.zhaopianlujing = zhaopianlujing;
guidata(hObject,handles);

3、车牌粗定位

车牌定位是车牌自动识别系统中非常重要的部分,复杂的背景和模糊的图片都给车牌定位带来困难,拥有良好的车牌识别系统性能不仅要求车牌定位的准确性高,而且定位的速度也要高。车牌的定位的方法的依据是车牌的诸多特点,在一张照片中找寻符合车牌特征的部分,并将其切割出来,实现车牌的定位。经过前人的研究,车牌定位主要有以下几种方法:
(1)根据车牌颜色信息的车牌定位。
(2)根据车牌纹理特征的车牌定位。
(3)根据边缘检测方法的车牌定位[。
(4)根据小波变换方法的车牌定位。
(5)综合多种方法的车牌定位。
本实验的车牌自动识别系统识别的车牌为蓝底白字车牌,针对我国蓝底白字车牌的颜色特征,本文的车牌粗定位算法是基于RGB颜色识别,寻找图片中蓝底白字车牌位置。根据车牌蓝底白字这一颜色特征,可以得出车牌所在位置有两个特点:(1)蓝色背景。(2)白色像素与车牌面积之比在一定范围之内。根据这两个特点可以得到疑似车牌所在区域。
因为一张车牌照片的背景可能很复杂,若仅仅根据车牌蓝底白字这一颜色特征来定位车牌,那么会出现很多错误定位。因此本文除了依靠车牌的颜色特征辨别车牌位置之外,还有车牌的形态特征,即定位出的车牌的长宽比要在允许范围之内。
运用车牌蓝底白字的颜色特征和长宽比的形状特征,对原始图片进行粗定位。

主代码:
[ydown,yup,xright,xleft]=first_location(yt);
[ydown,yup,xright,xleft,yuzhi]=xiuzheng(ydown,yup,xright,xleft);  %车牌区域根据面积二次修正
Plate = yt(yup:ydown,xleft:xright,:);
handles.Plate = Plate;   %放入handles结构体中,方便在其他回调函数中调用 第二张图片
guidata(hObject,handles);
bw=Plate;
子程序:
function [ydown,yup,xright,xleft]=first_location(img)
[y,x,~]=size(img);
img = double(img);  %转化为double型数据
y_yuzhi = 5;  %y的蓝色边界阈值
%在这里对于阈值的设置,阈值越大,截到的范围越小,为了避免车牌倾斜而导致切割掉有用部分,先设置一个较小的阈值,后面会对其进行二次切割。
%====================== Y 方向============================
y_lanse=zeros(y,1);
for b=1:y
    for c=1:x  
        if((img(b,c,1)<=48)&&((img(b,c,2)<=100)&&(img(b,c,2)>=40))&&((img(b,c,3)<=200)&&(img(b,c,3)>=80)))     %判断是否为蓝色RGB
           y_lanse(b,1)= y_lanse(b,1)+1;      % Y方向蓝色象素点统计                    
        end  
    end       
end
k=0;  %记录蓝色区域的循环次数
[~,y_max_hang] = max(y_lanse); % Y方向车牌区域,temp是最大值,MaxY是所在的行数。
yup=y_max_hang;    %有最多蓝点的行付给yup
while ((y_lanse(yup,1)>=y_yuzhi)&&(yup>1))%找到车牌上边界
    yup=yup-1;
end 
%yup 存储车牌上边界值
ydown=y_max_hang;
while ((y_lanse(ydown,1)>=y_yuzhi)&&(ydown<y))  %找到车牌下边界
     ydown=ydown+1;
end
%==============X 方向===============================
x_yuzhi=fix((ydown-yup)/11);  %向零舍入,这个数值很重要。决定了提取的彩图的质量,适当提高可抗干扰,但是小图会造成剪裁太多
x_lanse=zeros(1,x);             % 初始化蓝色矩阵
for c=1:x
    for b=yup:ydown   
        if((img(b,c,1)<=65)&&((img(b,c,2)<=100)&&(img(b,c,2)>=40))&&((img(b,c,3)<=160)&&(img(b,c,3)>=90)))%这里由82修改成90. 
         x_lanse(1,c)= x_lanse(1,c)+1;     %统计每列蓝色像素个数          
        end  
    end       
end
[~,x_max_lie]=max(x_lanse);  %temp是最大值,MaxX是最大值所在的列数。
xleft=x_max_lie-6*(ydown-yup);%这里根据长宽比得到初步边界。
if  xleft<=1     %防止溢出边界。
    xleft=1;
end
while ((x_lanse(1,xleft)<=x_yuzhi)&&(xleft<x))%确定X的左边起点。
      xleft=xleft+1;
end   
xright=x_max_lie+6*(ydown-yup);%得到初步的X右边边界。
if  xright>=x     %防止溢出边界。
    xright=x;
end
while ((x_lanse(1,xright)<=x_yuzhi)&&(xright>xleft))%%确定X的右边终点。
       xright=xright-1;
end

%=========================检验粗定位结果是否符合规范================================       
kuan=ydown-yup+1;chang=xright-xleft+1;
White=0;       %设置白色像素点变量
for b=yup:ydown
    for c=xleft:xright
        if (std([img(b,c,1) img(b,c,2) img(b,c,3)],1,2)<=22)&&(img(b,c,1)>=90)&&(img(b,c,1)<=255)  %std为求标准差函数
    %第三个参数代表的是按照列求标准差还是按照行求标准差,std(A,1,1)代表的是按照列求标准差,std(A,1,2)代表的是按照行求标准差。
            White= White+1;    % 白色象素点统计                    
        end  
    end       
end
bai_lan_bi=White/(kuan*chang);
kuan_chang_bi=kuan/chang;
k=k+1;
while(~((bai_lan_bi>=0.12)&&(bai_lan_bi<=0.5)&&(kuan_chang_bi>=0.20)&&(kuan_chang_bi<=0.6)))  %判断白蓝比与宽长比是否符合条件,若不符合则进入下面程序,继续判断。  
%===========================蓝色区域不是车牌区域=====================
% y_lanse(yup:ydowm,1)=0;   %在图片中将不是车牌区域置0
for m=yup:ydown
    for n=xleft:xright
        img(m,n,1)= 0;img(m,n,2)=0;img(m,n,3)=0;
    end
end
%防止陷入死循环
if (xright<=xleft)||(yup>=ydown)
    msgbox('粗定位出错','警告');
    pause(1);
    ydown=-5;
    break ;
end
end

车牌识别-基于模板匹配_第4张图片

4、灰度化

bw=rgb2gray(bw);
chepaihuidu = bw;
handles.chepaihuidu = chepaihuidu;     %第三张图片
guidata(hObject,handles);

车牌识别-基于模板匹配_第5张图片

5、倾斜矫正

因为拍照角度的不同,车牌经过粗略定位后,得到的图片中的车牌可能是倾斜的,所以首先要进行倾斜矫正。
倾斜矫正后的车牌图片中不仅有车牌信息,还有车牌的螺栓、边框、杂质等干扰信息。车牌精确定位的目的是去除车牌边框,清除干扰信息,获得更精确的车牌位置,为后面的字符分割和字符识别奠定基础。

主代码:
    %===========倾斜矫正=============
qingxiejiao=rando_bianhuan(bw);
bw=imrotate(bw,qingxiejiao,'bilinear','crop');%取值为负值向右旋转
jiaozhenghou = bw;
handles.jiaozhenghou = jiaozhenghou;     %第四张图片,车牌倾斜矫正后的图片
guidata(hObject,handles);
子程序:
function qingxiejiao=tilt_correct(I)
I=edge(I);%BW = edge(I) 返回二值图像 BW,其中的值 1 对应于灰度或二值图像 I 中函数找到边缘的位置,
%0 对应于其他位置。默认情况下,edge 使用 Sobel 边缘检测方法。
theta = 1:180;
[R,~] = radon(I,theta);%R = radon(I,theta) 返回基于 theta 所指定角度的 Radon 变换。
[~,J] = find(R>=max(max(R)));%J记录了倾斜角 find查找非零元素的索引和值
qingxiejiao=90-J;

车牌识别-基于模板匹配_第6张图片
车牌识别-基于模板匹配_第7张图片

6、二值化和第一次形态学处理

bw=im2bw(bw,graythresh(bw));   %graythresh函数找到二值化阈值
erzhihua = bw;
handles.erzhihua = erzhihua;     %第五张图片,二值化后的图片
guidata(hObject,handles);
%graythresh使用 Otsu 方法 [1] 根据灰度图像 I 计算全局阈值 T。
    % Otsu 方法选择一个阈值,使阈值化的黑白像素的类内方差最小化。
    % 全局阈值 T 可与 imbinarize 结合使用以将灰度图像转换为二值图像。
bw=bwmorph(bw,'open',5); %  执行形态学开操作(先腐蚀后膨胀)
xingtaixue = bw;
handles.xingtaixue = xingtaixue;   %第六张图片,第一次形态学处理后的图片
guidata(hObject,handles);

车牌识别-基于模板匹配_第8张图片
车牌识别-基于模板匹配_第9张图片

7、精确定位

现在图像的周围可能有多余的边框,可以用投影法去除上下左右的边框。
先进行水平投影,就是每一行在Y轴上的投影,会在水平边框部分和字符部分出现波峰,字符区域一定在两个波谷之间,由曲线的上下两个极大值分别从上而下和从下而上搜索波谷部分,由这两个波谷位置分割车牌。

主代码:
    %==========对图像进一步裁剪,保证边框贴近字体============
   bw=~bw;  %转化车牌信息的颜色
%==对图像进一步裁剪,保证边框贴近字体====
bw=touying(bw);
bw=~bw;     %车牌信息为白色
diercijiancai = bw;
handles.diercijiancai = diercijiancai;     %第七张图片,第二次剪裁后的图片
guidata(hObject,handles);
子程序:
function bw_fir = touying(imane_bw)   %反色图片,黑色为车牌信息,投影法修剪车牌照片。
X_yuzhi=1;
[y,x]=size(imane_bw);
Y_touying=(sum((~imane_bw)'))';%往左边投影统计黑点    再将车牌信息转化为白色
X_touying=sum((~imane_bw));%往下面投影
%找黑体边缘
Y_up=fix(y/2);       %0取整
Y_yuzhi=mean(Y_touying((fix(y/2)-10):(fix(y/2)+10),1))/1.6;  %mean求平均值,Y方向的阈值。
while ((Y_touying(Y_up,1)>=Y_yuzhi)&&(Y_up>1))%找到图片上边界  
       Y_up=Y_up-1;
end   
Y_down=fix(y/2);
while ((Y_touying(Y_down,1)>=Y_yuzhi)&&(Y_down<y))%找到图片下边界 
       Y_down=Y_down+1;
end
%去除左边边框干扰
 X_right=1;
 
if (X_touying(1,fix(x/14)))<=X_yuzhi
   X_right=fix(x/14);
end
%找黑体边缘
bw_fir=imane_bw(Y_up:Y_down,X_right:x);

车牌识别-基于模板匹配_第10张图片
车牌识别-基于模板匹配_第11张图片

8、第二次形态学处理

Bwareaopen函数:BW2=bareaopen(BW,P),从二值图像BW中删除小于P个像素的所有联通分量,并生成另一个二值图像BW2.

bw = bwareaopen(bw, yuzhi);     %移除小对象
dierciyichu = bw;
handles.dierciyichu = dierciyichu;     %第八张图片,第二次移除小对象后的图片
guidata(hObject,handles);

车牌识别-基于模板匹配_第12张图片
车牌识别-基于模板匹配_第13张图片

9、字符分割

字符分割即为将精确定位后得到的车牌分割为七个字符,每个字符的边界都不能有空白。若字符分割做得很好,那么字符识别的正确率将大大提高。同样地,字符分割的方法与车牌的特征紧密联系,不同的车牌特征衍生不同的分割方法。一般情况下,字符分割有以下几种方法:
(1)颜色法:颜色法由车牌的颜色特征产生的,比如蓝底白字的车牌,白色为字符且字符与字符之间不连续,白色和蓝色的不连续,这种方法对汉字分割有很好的效果。文献[12]强化车牌的颜色,提出模糊神经网络算法,利用这种算法,避免了使用单一阈值时产生的分割错误,增加了分割的正确率。
(2)连通区域法:连通区域法即先去除干扰,然后将不连通的字符做连通处理,最后查找连通区域,这些联通区域即为字符,从而达到分割字符的目的。这种方法对那些字符都是独立的情况有很好的效果,但对不独立的情况分割效果较差。
(3)车牌投影法:车牌投影法也有很多种,有很多文献对传统的投影法进行了改进,不仅使用车牌的投影特点,而且考虑了车牌字符的分布特点,设计出更好的算法,达到精确分割的目的。这种方法对有干扰的车牌也有很好的分割效果,而且精度很高。
(4)模板匹配法:根据车牌字符的排列特点,即字符与个空格等间距排列。模板匹配法使用两个模板,两个模板的宽度不同,一个为字符宽度,一个为空行的宽度。在分割时,移动两个模板,统计两个模板内的像素。将字符模板内的像素数与空格模板内的像素数相比,当为最大值时,则为字符分割点。该方法适合车牌照片有损失、车牌信息有扭曲的情况。
这里使用的分割方法为投影法。投影法的主要依据是车牌信息的水平排列特点,若将车牌信息垂直方向投影,那么可以发现投影的结果为“峰”“谷”“峰”形式,其中“峰”为字符,“谷”为分界点,所以本文字符分割使用投影法分割。
投影法的关键是分割阈值的选择,因为车牌图片的大小不一,所以阈值的选择和车牌的面积有关,根据不同的车牌面积选择相应的阈值,再将投影得到的值与阈值比较,进而得到字符位置,完成字符分割。

主程序:
    bw=~bw;%黑字白底
    [y,~]=size(bw);
    %============字符分割==============
fenge=zifufenge(bw);
    %==========剪裁7个字符============
    %给七张图片定位 ,将读取的字符信息分别赋值给7个数组
    han_zi=bw(1:y,fenge(1):fenge(2));
    zi_mu=bw(1:y,fenge(3):fenge(4));
    xuhao_1=bw(1:y,fenge(5):fenge(6));
    xuhao_2=bw(1:y,fenge(7):fenge(8));
    xuhao_3=bw(1:y,fenge(9):fenge(10));
    xuhao_4=bw(1:y,fenge(11):fenge(12));
    xuhao_5=bw(1:y,fenge(13):fenge(14));
    %======显示图像分割结果=======
   axes(handles.axes2);
imshow(han_zi);
axes(handles.axes15);
imshow(zi_mu);
axes(handles.axes16);
imshow(xuhao_1);
axes(handles.axes17);
imshow(xuhao_2);
axes(handles.axes18);
imshow(xuhao_3);
axes(handles.axes19);
imshow(xuhao_4);
axes(handles.axes20);
imshow(xuhao_5);
子函数zifufenge:
function fenge = zifufenge(imfenge)       %车牌信息为黑色
[y,x]=size(imfenge);
%将计算得到车牌区域分割后的图象,对白色进行水平垂直投影,计算水平垂直峰, 检测合理的字符高宽比.
%可用与区域分割相同的方法进行峰值的删除和合并
%对切割出的字符宽度进行统计分析,用以指导切割,对因错误切割过宽的字符进行分裂处理
%针对分割出来的字体的宽度与整个车牌的宽度对比,对误操作字符进行合并

%===============用函数设定分割阈值========================
SS=x*y;         %根据不同的面积设定阈值
shedingyuzhi=4;
ganrao=SS/100;
%=========================================================
%定义数组histogram存储垂直方向的黑点数
histogram=sum(~imfenge);     %转换为白色,统计车牌像素数

%figure(6);
plot(1:x,histogram);%plot(X,Y) 创建 Y 中数据对 X 中对应值的二维线图。
%=================文字分割=============================
k=1;
for h=1:x-1
    if  ((histogram(1,h)<=shedingyuzhi)&&(histogram(1,h+1)>shedingyuzhi))||((h==1)&&histogram(1,h)>shedingyuzhi)
        fenge(1,k)=h;      %储存分割左边界列数
        k=k+1;
    elseif ((histogram(1,h)>shedingyuzhi)&&(histogram(1,h+1)<=shedingyuzhi))||((h==x-1)&&histogram(1,h)>shedingyuzhi)
        fenge(1,k)=h+1;    %储存分割右边界列数
        k=k+1;
    end
end
k=k-1;%去掉多产生的一个K值
%==============================================
if (sum(histogram(1,fenge(1,1):fenge(1,2)))<ganrao)||((fenge(1,2)-fenge(1,1))<(fenge(1,4)-fenge(1,3))/2)       %如果车牌分割的部分出现了干扰
    for i=3:k                    %去除第一个分割点
        fenge(1,i-2)=fenge(1,i);
    end
end
[~,n]=size(fenge);         %完美分割时,n==14
if  n<14
    msgbox('分割出错','警告');
    sound(audioread('提取出错.wav'),48000);
    pause(1);
end
fenge=fenge(1,1:14);   %只返回十四个分割节点

车牌识别-基于模板匹配_第14张图片

10、归一化切割后的字符以及模板

因为分割后的字符大小不一,为了统一字符大小便于之后统计相同像素点,所以要将切割后的字符归一化。使用imrerize函数调整图片的大小为统一大小,本实验统一大小为110×70.

11、字符匹配

字符识别的方法有很多,主要可分为:特征匹配法,模板匹配法和神经网络法。本次实验使用的是模板匹配法,将模板字符和切割后的字符进行归一化后,逐个像素的比较二者的值,统计相同的像素点,像素点最多的模板就是该字符的识别结果。

主函数:
    %========识别结果==========

    jieguohanzi  = shibiehanzi(muban_hanzi,guiyihua_hanzi); %在shibiehanzi.m文件中创建函数,输入归一化后的切割汉字和模板汉字,输出识别结果      
    shibiejieguo(1) =jieguohanzi;  i=2;
    jieguozimu   = shibiezimu(muban_zimu,guiyihua_zimu);           
    shibiejieguo(i) =jieguozimu;   i=i+1;
    shibiejieguo(i) ='·';   i=i+1;
    jieguozm_sz_1= shibiezm_sz(muban_shuzizimu,guiyihua_xuhao1);   shibiejieguo(i) =jieguozm_sz_1;i=i+1;
    jieguozm_sz_2= shibiezm_sz(muban_shuzizimu,guiyihua_xuhao2);   shibiejieguo(i) =jieguozm_sz_2;i=i+1;
    jieguozm_sz_3= shibiezm_sz(muban_shuzizimu,guiyihua_xuhao3);   shibiejieguo(i) =jieguozm_sz_3;i=i+1;
    jieguozm_sz_4= shibiezm_sz(muban_shuzizimu,guiyihua_xuhao4);   shibiejieguo(i) =jieguozm_sz_4;i=i+1;
jieguozm_sz_5= shibiezm_sz(muban_shuzizimu,guiyihua_xuhao5);   shibiejieguo(i) =jieguozm_sz_5;
handles.shibiejieguo=shibiejieguo;
guidata(hObject,handles);

set(handles.chepai,'string',shibiejieguo);  

%=====================导出文本==================
fid=fopen('Data.dat','a');
fprintf(fid,'%s\r\n',shibiejieguo,datestr(now));
fclose(fid);

子函数shibiehanzi
function shibiehanzi=shibiehanzi(muban_hanzi,fenge_hanzi)           %车牌信息为黑色
[y,x,~]=size(fenge_hanzi);
for k=1:27
    sum=0;
    for i=1:y
        for j=1:x
            if  muban_hanzi(i,j,k)==fenge_hanzi(i,j)%统计黑白匹配程度
                sum=sum+1;
            end
        end
    end
    tongji(k)=sum;  %储存相同点的个数
end
num = find(tongji>=max(tongji));  %find函数返回的是非0的序数,返回由结果的线性索引组成的列向量
%在数字中,从0开始所以要减一。这里不用
switch num(1)
    case 1
        shibiehanzi = '鄂';
    case 2
        shibiehanzi = '赣';
    case 3
        shibiehanzi = '甘';
    case 4     
        shibiehanzi = '桂';
    case 5
        shibiehanzi = '贵';
    case 6
        shibiehanzi = '黑';
    case 7
        shibiehanzi = '吉';
    case 8
        shibiehanzi = '晋';
    case 9
        shibiehanzi = '京';
    case 10
        shibiehanzi = '辽';
    case 11
        shibiehanzi = '鲁';
    case 12
        shibiehanzi = '蒙';
    case 13
        shibiehanzi = '闽';
    case 14
        shibiehanzi = '宁';
    case 15
        shibiehanzi = '青';
    case 16
        shibiehanzi = '琼';
    case 17
        shibiehanzi = '陕';
    case 18
        shibiehanzi = '苏';
    case 19
        shibiehanzi = '津';
    case 20
        shibiehanzi = '皖';
    case 21
        shibiehanzi = '湘';
    case 22
        shibiehanzi = '豫';
    case 23
        shibiehanzi = '粤';
    case 24
        shibiehanzi = '云';
    case 25
        shibiehanzi = '藏';
    case 26
        shibiehanzi = '浙';
    case 27
        shibiehanzi = '冀';
    otherwise
        shibiehanzi = '错';
end

子函数shibiezimu
function shibiezimu=shibiezimu(zimu,xiuzhengzimu)
[y,x,~]=size(xiuzhengzimu);
for k=1:24
    sum=0;
    for i=1:y
        for j=1:x
            if  zimu(i,j,k)==xiuzhengzimu(i,j)  %统计匹配程度
                sum=sum+1;
            end
        end
    end
baifenbi(1,k)=sum/(x*y);
end
chepai= find(baifenbi>=max(baifenbi));
shibiezimu=chepai;   %在数字中,从0开始所以要减一。这里不用
if         shibiezimu==1
        shibiezimu='A';
    elseif shibiezimu==2
        shibiezimu='B';
    elseif shibiezimu==3
        shibiezimu='C';
    elseif shibiezimu==4
        shibiezimu='D';
    elseif shibiezimu==5
        shibiezimu='E';
    elseif shibiezimu==6
        shibiezimu='F';
    elseif shibiezimu==7
        shibiezimu='G';
    elseif shibiezimu==8
        shibiezimu='H';
    elseif shibiezimu==9
        shibiezimu='J';
    elseif shibiezimu==10
        shibiezimu='K';
    elseif shibiezimu==11
        shibiezimu='L';
    elseif shibiezimu==12
        shibiezimu='M';
    elseif shibiezimu==13
        shibiezimu='N';
    elseif shibiezimu==14
        shibiezimu='P';
    elseif shibiezimu==15
        shibiezimu='Q';
    elseif shibiezimu==16
        shibiezimu='R';
    elseif shibiezimu==17
        shibiezimu='S';
    elseif shibiezimu==18
        shibiezimu='T';
    elseif shibiezimu==19
        shibiezimu='U';
    elseif shibiezimu==20
        shibiezimu='V';
    elseif shibiezimu==21
        shibiezimu='W';
    elseif shibiezimu==22
        shibiezimu='X';
    elseif shibiezimu==23
        shibiezimu='Y';
    elseif shibiezimu==24
        shibiezimu='Z';
end

子函数shibiezm_sz
function shibiezm_sz=shibiezm_sz(shuzizimu,xiuzhengzm_sz)
[y,x,~]=size(xiuzhengzm_sz);
   
for k=1:34
    sum=0;
    for i=1:y
        for j=1:x
            if  shuzizimu(i,j,k)==xiuzhengzm_sz(i,j) %统计匹配程度
                sum=sum+1;
            end
        end
    end
    baifenbi(1,k)=double(sum/(x*y));
end
chepai= find(baifenbi>=max(baifenbi));  
%===================数字直接返回=========================

if (chepai(1)>=1)&&(chepai(1)<=10)
       zm_sz=chepai(1)-1;
       zm_sz=num2str(zm_sz);%s = num2str(A) 将数值数组转换为表示数字的字符数组。
       % 输出格式取决于原始值的量级。num2str 对使用数值为绘图添加标签和标题非常有用。
else
%==================字母对应序号转字母====================
%=========11-15 ABCDE 16-20FGHIJ 21-25 KLMNP 26-30 QRSTU 31-35 VWXYZ
    if     chepai(1)==11
         zm_sz='A';
    elseif chepai(1)==12
         zm_sz='B';
    elseif chepai(1)==13
         zm_sz='C';
    elseif chepai(1)==14
         zm_sz='D';
    elseif chepai(1)==15
         zm_sz='E';
    elseif chepai(1)==16
         zm_sz='F';
    elseif chepai(1)==17
         zm_sz='G';
    elseif chepai(1)==18
         zm_sz='H';
    elseif chepai(1)==19
         zm_sz='J';
    elseif chepai(1)==20
         zm_sz='K';
    elseif chepai(1)==21
         zm_sz='L';
    elseif chepai(1)==22
         zm_sz='M';
    elseif chepai(1)==23
         zm_sz='N';
    elseif chepai(1)==24
         zm_sz='P';
    elseif chepai(1)==25
         zm_sz='Q';
    elseif chepai(1)==26
         zm_sz='R';
    elseif chepai(1)==27
         zm_sz='S';
    elseif chepai(1)==28
         zm_sz='T';
    elseif chepai(1)==29
         zm_sz='U';
    elseif chepai(1)==30
         zm_sz='V';
    elseif chepai(1)==31
         zm_sz='W';
    elseif chepai(1)==32
         zm_sz='X';
    elseif chepai(1)==33
         zm_sz='Y';
    elseif chepai(1)==34
         zm_sz='Z';        
    end
end
shibiezm_sz=zm_sz;

车牌识别-基于模板匹配_第15张图片

12、语音播报

Audioread读取音频文件,sound将信号数据矩阵转换为声音。

主程序:
%点击语音播报执行的函数
function sound_Callback(hObject, eventdata, handles)
duchushengyin(handles.shibiejieguo);
子函数:
function shengyin=duchushengyin(shibiejieguo)
sound(audioread('检测结果.wav'),48000); %sound(y,Fs) 以采样率 Fs 向扬声器发送音频信号 y
pause(3);
for i=1:8
    if     shibiejieguo(1,i)=='桂'
          sound(audioread('桂.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='贵'
           sound(audioread('贵州.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='京'
           sound(audioread('京.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='粤'
           sound(audioread('粤.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='苏'
           sound(audioread('苏.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='吉'
           sound(audioread('吉.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='鄂'
           sound(audioread('鄂.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='赣'
           sound(audioread('赣.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='甘'
           sound(audioread('甘.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='黑'
           sound(audioread('黑.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='晋'
           sound(audioread('晋.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='辽'
           sound(audioread('辽.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='鲁'
           sound(audioread('鲁.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='蒙'
           sound(audioread('蒙.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='闽'
           sound(audioread('闽.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='宁'
           sound(audioread('宁.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='青'
           sound(audioread('青.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='琼'
           sound(audioread('琼.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='陕'
           sound(audioread('陕.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='津'
           sound(audioread('津.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='皖'
           sound(audioread('皖.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='湘'
           sound(audioread('湘.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='豫'
           sound(audioread('豫.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='云'
           sound(audioread('云.wav'),48000);pause(2);
    elseif shibiejieguo(1,i)=='藏'
           sound(audioread('藏.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='浙'
           sound(audioread('浙.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='冀'
           sound(audioread('冀.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='A'
	   sound(audioread('A.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='B'
	   sound(audioread('B.wav'),48000); pause(1);
    elseif shibiejieguo(1,i)=='C'
	   sound(audioread('C.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='D'
	   sound(audioread('D.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='E'
	   sound(audioread('E.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='F'
	   sound(audioread('F.wav'),48000); pause(1);
    elseif shibiejieguo(1,i)=='G'
	   sound(audioread('G.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='H'
	   sound(audioread('H.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='J'
	   sound(audioread('J.wav'),48000);  pause(1);
    elseif shibiejieguo(1,i)=='K'
	   sound(audioread('K.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='L'
	   sound(audioread('L.wav'),48000);  pause(1); 
    elseif shibiejieguo(1,i)=='M'
	   sound(audioread('M.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='N'
	   sound(audioread('N.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='P'
	   sound(audioread('P.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='Q'
	   sound(audioread('Q.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='R'
	   sound(audioread('R.wav'),48000); pause(1);
    elseif shibiejieguo(1,i)=='S'
	   sound(audioread('S.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='T'
	   sound(audioread('T.wav'),48000);   pause(1); 
    elseif shibiejieguo(1,i)=='U'
	   sound(audioread('U.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='V'
	  sound(audioread('V.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='W'
	   sound(audioread('W.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='X'
	   sound(audioread('X.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='Y'
	   sound(audioread('Y.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='Z'
	  sound(audioread('Z.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='0'
	  sound(audioread('0.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='1'
	  sound(audioread('1.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='2'
	 sound(audioread('2.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='3'
	  sound(audioread('3.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='4'
	  sound(audioread('4.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='5'
	  sound(audioread('5.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='6'
	  sound(audioread('6.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='7'
	   sound(audioread('7.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='8'
	 sound(audioread('8.wav'),48000);pause(1);
    elseif shibiejieguo(1,i)=='9'
	  sound(audioread('9.wav'),48000);pause(1);
    end
end
sound(audioread('车牌检测.wav'),48000);

13、退出系统和关于按钮

点击按钮调用对应的回调函数,%questdlg创建问题对话框,answer = questdlg(quest) 创建一个模态对话框,其中提出问题并返回用户的回答 - ‘Yes’、‘No’、‘Cancel’ 或 ‘’。默认情况下,该对话框有三个标准按钮,其标签分别为是、否和取消。如果用户点击其中一个按钮,则 answer 值与按下的按钮的标签相同。如果用户点击对话框标题栏上的关闭按钮 (X) 或按下 Esc 键,则 answer 值为空字符向量 (’ ')。如果用户按下 Return 键,则 answer 值与默认所选按钮的标签相同。
Msgbox创建消息对话框,显示本次实践主题。增加交互体验。

%questdlg创建问题对话框
%answer = questdlg(quest) 创建一个模态对话框,其中提出问题并返回用户的回答 - 'Yes''No''Cancel'''%默认情况下,该对话框有三个标准按钮,其标签分别为是、否和取消。
%如果用户点击其中一个按钮,则 answer 值与按下的按钮的标签相同。
%如果用户点击对话框标题栏上的关闭按钮 (X) 或按下 Esc 键,则 answer 值为空字符向量 (' ')%如果用户按下 Return 键,则 answer 值与默认所选按钮的标签相同。
function exit_Callback(hObject, eventdata, handles)
button=questdlg('确定退出系统吗?','确认','No');  %当按回车键时,返回default,default 必须是yes,no或cancel 之一。
if strcmp(button,'Yes')%tf = strcmp(s1,s2) 比较 s1 和 s2,如果二者相同,则返回 1 (true),否则返回 0 (false)。
    close all;
end

function about_Callback(hObject, eventdata, handles)
str={'车牌识别系统'};
% 改变msgbox属性
% 寻找句柄,改变属性
hs = msgbox(str,'关于');
%findobj查找具有特定属性的图形对象
ht = findobj(hs, 'Type', 'text');%返回所有文本类型的对象
set(ht, 'FontWeight', 'bold','FontSize',12);%设置图形对象属性,将字符粗细设置为加粗,将字体大小设置为12

车牌识别-基于模板匹配_第16张图片
车牌识别-基于模板匹配_第17张图片

三、总的操作图

![原图车牌识别-基于模板匹配_第18张图片

车牌识别-基于模板匹配_第19张图片
车牌识别-基于模板匹配_第20张图片
车牌识别-基于模板匹配_第21张图片
车牌识别-基于模板匹配_第22张图片
车牌识别-基于模板匹配_第23张图片
车牌识别-基于模板匹配_第24张图片
车牌识别-基于模板匹配_第25张图片

你可能感兴趣的:(matlab,开发语言)