@Aurora-xi
2019-07-12T13:30:36.000000Z
字数 5172
阅读 747
图像处理 车牌识别 字符分割
自动识别文字的技术是模式识别应用领域的一个重要研究方向,是文字分析技术和图像处理相结合的一门新型专业领域。文字识别的一般方法在20世纪50年代开始出现,经历了60多年的研究,成功的完成了从实验室技术到产品的转换,关键技术有去燥处理、文字定位、字符分割等。
字符分割的方法较多。基于结构的分割方法,常用的有连通域分割法,该方法首先对前景像素进行扫描,使其形成连通域,然后对这些连通域根据已经设置好的条件进行合并和裁剪,最后剩余下来的连通域为相应的字符图片。基于统计特征的常用方法为直方图投影法,该方法根据相邻字符之间具有一定的间隔来对字符进行分割,可以较为直观地得到分割点。
以车牌字符提取为例,在进行滤波等操作之后,还要将车牌的区域位置大致提取出来,之后将预处理之后的图像边缘计算出来,算出该边缘图像的投影面积,再通过寻找谷峰点的大致位置最终确定获取到的原始图像中车牌的位置。确定车牌位置之后,系统就要对该区域的图像中的字符进行分割,分割主要是通过对投影的检测,确定每个字符位置,通过分割得到单个的字符。
要实现车牌识别,首先要从计算机中读取含有要识别车牌的图片,我们通过imread函数将图像数据读出,赋值给变量I,从而实现图像数据的读入。
I=imread('D:\学习\数字图像处理\MATLAB代码\test1.jpg');
figure(1);
subplot(2,2,1),imshow(I);title('原图');

彩色图像由三个不同的分量组成,称为三通道图像。对彩色图像进行处理时,往往需要对三个通道依次进行处理,时间开销将会很大。因此,为了提高处理速度,需要减少所需处理的数据量。
灰度化就是把由RGB三通道数据组成的彩色图像变为单通道的灰度图像。在RGB模型中,如果R、G、B三者的值相等,即使是三通道数据,也是表现出一种灰度颜色,灰度值就是R、G、B的值。可以发现,当R、G、B三者相等时,我们只需一个字节存放该灰度值即可。
这里使用了rgb2gray函数进行图像的灰度转换,该函数接收一个rgb图像变量作为参数,返回该图像转换为灰度图后的图像数据。
若想观察该灰度图的灰度分布情况,可使用imhist函数画出该灰度图的灰度值分布直方图。
I1=rgb2gray(I); %转换为灰度图像
subplot(2,2,2),imshow(I1);title('灰度图');
subplot(2,2,3),imhist(I1);title('灰度图直方图');%观察灰度图的灰度分布情况

在将彩色图转换为灰度图后,便可用edge函数识别该图像的边界,edge函数通过使用一阶导数和二阶导数检测亮度的不连续来确定图像的边界,它可以使用Sobel,Prewitt,Roberts,Canny,LoG,零交叉等多种算子。
I2=edge(I1,'canny',0.08,'both');
subplot(2,2,4),imshow(I2);title('canny算子边缘检测')

由于边缘检测后的图像中无关结构太多,这里需对图像进行腐蚀处理,也就是在二值图像的基础上收缩、细化。
实现腐蚀处理的函数为imerode,它接收一个图像数据和一个结构子,图像中背景与结构子完全重合的像素点输出值为1,不完全重合的和完全不重合的像素点输出值为0,最后返回使用该结构子腐蚀过后的图像数据,以此实现削减无关结构的目的。
se=[1;1;1]; %线型结构元素
I3=imerode(I2,se); %腐蚀

腐蚀后的图像结构大多呈分散状分布,不连贯。为了方便之后确认车牌位置,这里需对该图像进行平滑处理,在此我们使用闭操作使车牌平滑,并减小噪音,闭操作可以理解为先膨胀后腐蚀,实现函数为imclose。
se=strel('rectangle',[40,40]);%生成一个矩阵 线型结构元素
I4=imclose(I3,se); %闭运算,先膨胀后腐蚀

在上图中不仅提取出了车牌的大致范围,也提取出了其他的一些小面积对象,这一步要把小面积对象去掉,从而使车牌位置的确定更加精确。这里使用了MATLAB的bwareaopen函数从图象中删除小面积对象。
I5=bwareaopen(I4,2000,8);%删除小面积对象
subplot(2,2,3),imshow(I5);title('从图象中移除小对象');
subplot(2,2,4),imhist(I5);title('灰度图直方图');

在经过上面的处理之后,最初要识别的彩色图像已经变成了以车牌为主要结构的二值图像,我们可以对这种主体结构清晰的二值图像进行扫描,进而确定出车牌的位置。
这里确定车牌位置的思路为:
以下为确定车牌位置的具体代码
[y,x]=size(I5); %得到该图像矩阵的行数y和列数x
myI=double(I5);
white_y=zeros(y,1);
for i=1:y %遍历每一行的像素点
for j=1:x
if(myI(i,j,1)==1)
white_y(i,1)= white_y(i,1)+1;%白色像素点统计
end
end
end
%认为白色像素最多的行为车牌中心行
[temp,MaxY]=max(white_y);%temp为向量white_y的元素中的最大值,MaxY为对应的行
PY1=MaxY;
while ((white_y(PY1,1)>=120)&&(PY1>1))
PY1=PY1-1; %找车牌最上端
end
PY2=MaxY;
while ((white_y(PY2,1)>=40)&&(PY2<y))
PY2=PY2+1; %找车牌最下端
end
%同样方式纵向扫描
white_x=zeros(1,x);%进一步确定x方向的车牌区域
for j=1:x
for i=PY1:PY2
if(myI(i,j,1)==1)
white_x(1,j)= white_x(1,j)+1;
end
end
end
PX1=1; % 找车牌X方向最小值,即车牌最左端
while ((white_x(1,PX1)<3)&&(PX1<x))
PX1=PX1+1;
end
PX2=x; % 找车牌X方向最大值,即车牌最右端
while ((white_x(1,PX2)<3)&&(PX2>PX1))
PX2=PX2-1;
end
通过以上定位,我们得到了车牌的上边界PY1,下边界PY2,左边界PX1,右边界PX2,我们可以通过这四个边界值从原彩色图像中切割出车牌。
dw=I(PY1:PY2,PX1:PX2,:); %切割出车牌
figure(3),subplot(2,2,1),imshow(dw),title('定位剪切后的彩色车牌图像')

在得到车牌的彩色图像之后,为了便于将其中的字符分离,我们将它转换为二值图像。首先将彩色图像转换为灰度图像,再确定合适的阈值(此处根据资料,最佳阈值取灰度的最大值减去最大值与最下值的1/3梯度)
b=rgb2gray(a); %彩色图像转换为灰度图像
subplot(2,2,2),imshow(b),title('车牌灰度图像')
g_max=double(max(max(b)));
g_min=double(min(min(b))); %换成双精度数值
T=round(g_max-(g_max-g_min)/3); %T为二值化的阈值
d=(double(b)>=T); %d即二值图像
subplot(2,2,3),imshow(d),title('车牌二值图像')

在车牌转换为二值图像后,为了使图像中干扰元素减少,我们对其进行均值滤波,通过fspecial函数构造均值滤波器,然后使用filter2函数进行滤波,以减小图中噪音。
h=fspecial('average',3); %均值滤波器
d=im2bw(round(filter2(h,d)));
subplot(2,2,4),imshow(d),title('均值滤波后')

由于不同原始图像的差异,处理到这里后,字符可能会不连续,也可能会连在一起,这时我们需要再次对滤波后的图像进行腐蚀或者膨胀处理,这里使用判断结构以图中白色部分的面积为判断依据决定使用腐蚀或者膨胀。
se=eye(2); %
[m,n]=size(d);
if bwarea(d)/m/n>=0.365 %计算二值图像中白的对象占总面积
c=imerode(d,se); %imerode 实现图像腐蚀 d为待处理图像,se是结构元素对象
elseif bwarea(d)/m/n<=0.235
c=imdilate(d,se); %imdilate 图像膨胀
end

在分离字符之前,我们还要切去车牌边缘的黑色部分,在这里我们定义了一个用于切割的函数qiege,思路如下:
从图像顶部向底部逐行扫描,对扫描到的行求和,若某行全部像素点求和为0(即该行所有像素点均为黑色),则切去这一行,直到扫描到某一行求和后值不为零,以这一行为上边界。
同理,再用相同的方法从其他三个方向扫描,切割出下边界,左边界和·右边界,最后得到切去边缘黑色部分的图像。
function e=qiege(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]);
end

将切割过后,就可以对图片中的字符进行分离了,这里我们定义了一个用于分离字符的函数getword,思路如下:
对图像从左到右逐列扫描,并将每列中像素点的值进行求和,若和不为零(即这一列是组成某字符的一列),则向右继续扫描下一列,直到某一列求和后值为零(即这一列是两白色字符之间的黑色间隔),图像最左侧到这一列之间即为第一个字符,将其切出,然后将该区域内所有像素点赋值为0(涂黑),重复以上操作直至分离出所有字符。
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 %有白色加1知道没有白色,也就是找出一个白色区域
wide=wide+1;
end
temp=qiege(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=qiege(d); % 切割出最小范围
else word=[];flag=1;
end
else
word=qiege(imcrop(d,[1 1 wide m]));
d(:,[1:wide])=0;
if sum(sum(d))~=0;
d=qiege(d);flag=1;
else d=[];
end
end
end
result=d;
end
d=im2bw(round(filter2(h,d)));
subplot(2,2,4),imshow(d),title('均值滤波后')
