【车牌识别】基于matlab模板匹配新能源车牌识别【含Matlab源码 865期】

201 阅读4分钟

一、简介

1 在进行图像处理任务之前,首先要明确处理对象和处理流程
处理对象: 新能源车牌和蓝色车牌
处理流程:
在这里插入图片描述
2 由于要对蓝色和新能源车牌进行识别,而且新能源车牌是渐变色,所以直接通过设定阈值的方法去识别两种车牌并没有单独识别蓝色车牌的可靠性高。这里,我根据车牌字符的特征进行车牌位置定位:
2.1 根据字符特征初步找出车牌位置
在这里插入图片描述
2.2 根据车牌长宽比进行初步筛选
我们可以用最小外接矩形算法框出上一步已选出的区域,然后根据车牌长宽比设定阈值,将满足阈值的矩形筛选出来,当然但还是会存在一部分干扰区域。

2.3 对矩形内像素进行颜色统计
通过对初步筛选后剩余区域分别进行像素的颜色统计,我们即可准确找出车牌位置,与此同时车牌的类型(新能源或蓝牌)也可以在这里判断出来

3 倾斜校正
这一步是为后面垂直投影法分割字符和模板匹配做准备

简单来讲,使用霍夫线算法检测车牌上下边框所在直线,计算这条直线倾斜角度,之后对车牌进行旋转即可。当然复杂点的方法可以具体看我的源程序,具体效果如下图:
在这里插入图片描述

4 二值化、形态学处理、字符识别
4.1 二值化和形态学处理这里就不在赘述,很多博客已经讲的非常清晰
4.2 字符分割
在这里需要对字符进行准确的分割,在分割之前还是可能会有干扰,需要再次分割出车牌字符的准确位置。这里我的方法是:先向左投影,设定阈值,切割出上下边界,同理在切割出左右边界。但是这只适用于车牌边框明显的情况下,所以我不建议你使用这个方法,慎用!!!
在这里插入图片描述
到这里就可以使用垂直投影法进行字符分割,这里需要注意的是新能源车牌有八位,蓝牌有七位
分割结果如下图所示:
在这里插入图片描述
4.3 字符识别
这里使用模板匹配,因为新能源车牌字符和蓝牌字符不一致,所以要制作两套字符模板。另外需要注意的是,根据《中华人民共和国机动车号牌》序号编码规则,26个英文字符中“I“、”O“不能使用,所以不存在"1"和"I"、"0"和"O"字符混淆的问题

二、源代码

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% resize的目标尺寸650*X
% 调参
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear;


se1 = strel('rectangle',[15 15]);                                 %创建一个平坦的矩形结构
se2 = strel('rectangle',[12 20]);                                 %创建一个平坦的矩形结构
se3 = strel('rectangle',[12 15]);
imgraw=imread('C:\Users\lenovo\Desktop\licenseplate\0.png');                %读取图

% se1 = strel('rectangle',[15 25]);                                 %创建一个平坦的矩形结构
% se2 = strel('rectangle',[10 25]);                                 %创建一个平坦的矩形结构
% se3 = strel('rectangle',[14 19]);
% imgraw=imread('E:\matlab workspace\licenseplate\车牌2.jpg');                %读取图像


[m,~]=size(imgraw);
times = 650/m;
img=imresize(imgraw,times,'nearest');
g= fspecial('gaussian',[5,5],1);                                  %高斯滤波器
g_img = imfilter(img, g, 'replicate');                            %图像滤波
gray_img=rgb2gray(g_img);                                         %转为灰色图像        
open = imopen(gray_img,se1);                                      %图像开操作
sub_img = imsubtract(gray_img,open);                              %图像相减
BW_img = imbinarize(sub_img);                                     %使用Otsu方法确定全局阈值进行二值化
edge_img = edge(BW_img,'canny');
edge_img1 = imclose(edge_img,se2);                                %图像闭操作
edge_img2 = imopen(edge_img1,se3);                                %图像开操作

%%%%%%%%%%%%%%%%%%%%%%%%%%%使用车牌长宽比进行判断%%%%%%%%%%%%%%%%%%%%%%%%%%%

[B,L] = bwboundaries(edge_img2,'noholes');  
num_rect = 0;                                                               %符合要求的矩形数量
matrix_rect = {};                                                           %符合要求的矩形的坐标元胞矩阵
for k = 1:length(B)
    boundary = B{k};
    c = boundary(:,2);
    r = boundary(:,1);
    [rectx,recty,area,perimeter] = minboundrect(c,r,'a');                    %rectx,recty为逆时针排列
    width = round(sqrt((recty(1)-recty(2))^2+(rectx(1)-rectx(2))^2));
    leth = round(sqrt((recty(2)-recty(3))^2+(rectx(2)-rectx(3))^2));
    if width > leth
        temp = width;
        width = leth;
        leth = temp;
    end
    ratio = leth / width;
    if ratio >2.5 && ratio <4.5
        num_rect = num_rect + 1;
        matrix_rect{num_rect} = [rectx,recty];
    end      
end    

subplot(451); imshow(img); title('原始图像');
subplot(452); imshow(g_img);    title('高通滤波后图像');
subplot(453); imshow(gray_img);    title('灰度图像');
subplot(454); imshow(open);    title('图像开操作');
subplot(455); imshow(sub_img);    title('图像相减');
subplot(456); imshow(BW_img);    title('图像二值化');
subplot(457); imshow(edge_img);    title('图像边缘');
subplot(458); imshow(edge_img2);    title('图像开闭操作');
subplot(459); imshow(img);    title('原图框出车牌');
hold on
for k = 1:num_rect
    rect = matrix_rect{k};
    rx = rect(:,1);
    ry = rect(:,2);
    line(rx,ry,'Color','red');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%判断颜色、二次判断车牌%%%%%%%%%%%%%%%%%%%%%%%%%%%

p=0;  %计算满足颜色条件的次数
color = 'no';
for o=1:num_rect
    z=matrix_rect{o};
    mid1x=(z(1,1)+z(2,1))/2;
    mid1y=(z(1,2)+z(2,2))/2;
    mid2x=(z(3,1)+z(4,1))/2;
    mid2y=(z(3,2)+z(4,2))/2;
    green=0;blue=0;
    hsv= rgb2hsv(img);  %RGB转换为HSV
    img_count = (abs(ceil(mid2x+0.601)-floor(mid1x+0.601)))*(abs(ceil(mid2y+0.001)-floor(mid1y+0.001)));
    subplot(4,5,10);  imshow(hsv);

    for i=ceil(mid1y+1):floor(mid2y-1)
        if mid2x==mid1x
            for j=floor(mid2x+1):ceil(mid1x+1)
                h = hsv(i,j,1);
                s = hsv(i,j,2);
                v = hsv(i,j,3);
                if 0.40< h && h <= 0.46 &&  s>0.4 && s<=1 && v>0.3 && v<1
                    green = green+1;
                elseif 0.56<h && h<=0.72 && s>0.4 && s<=1 && v>0.4 && v<1
                    blue =blue +1;                
                end
            end       
            
        else
            for j=ceil(mid2x+1):floor(mid1x-1)
                h = hsv(i,j,1);
                s = hsv(i,j,2);
                v = hsv(i,j,3);

                if 0.40< h && h <= 0.46 &&  s>0.4 && s<=1 && v>0.3 && v<1
                    green = green+1;
                elseif 0.56<h && h<=0.72 && s>0.4 && s<=1 && v>0.4 && v<1
                    blue =blue +1;                
               end
            end
        end
    end
    if green*2 >= img_count && green>blue
        color = 'green';
        p=p+1;
        b=z;   %满足条件的元胞
    elseif blue*2 >= img_count && blue>green
        color = 'blue';
        p=p+1;
        b=z;   %满足条件的元胞
    end
end

if (color == 'blue')&&(p == 1)
    flag = 0;
    style = '识别到的是蓝色';
elseif (color == 'green')&&(p == 1)
    flag = 1;
    style = '识别到的是新能源';
end
function image=cutting(img,flag) 
    %获取图片大小
    [row,col] = size(img); 
    %设定边界
    img(:,col)=1;
    img(:,1)=1; 
    %图像取反,方便后续处理,根据黑色判断边界
    all = sum(~img);  %行向量
    %figure('NumberTitle','off','Name','投影'),bar(a),title('投影');
    left = 1;
    right = 1;
    count1 =0; %记录字符个数
    for i = 1:col-1  %从左到右扫描
        if all(i)==0&&all(i+1)~=0 %左侧边界
            left = i;
        end
        if all(i)~=0&&all(i+1)==0 %右侧边界
            right=i;
        else
            right =0; %左右两侧均为黑色边框
        end
        if right~=0
            count1 = count1+1;
            left_bound(count1) = left; %存放左边界
            right_bound(count1) = right; %存放右边界
        end    
    end
    for i = 1:count1 %???
        if left_bound(i)<fix(col/8)
            left_bound(i)=left_bound(1);
        end
    end
    count2 =1; %k记录满足条件的字符个数
    right_boundary = zeros(1,count1); %存放右边界
    left_boundary = zeros(1,count1); %存放左边界
    for i = 1:count1
        if (right_bound(i) - left_bound(i))>(fix(col/15)) %判断字符宽度是否满足要求 问题:字符宽度怎么求
            right_boundary(count2) = right_bound(i);
            left_boundary(count2) = left_bound(i);
            count2 = count2+1;
        end
    end

三、运行结果

在这里插入图片描述

四、备注

版本:2020