传入一张二值车牌图像。其像素大小为50x194 double类型
当我们对这个图像进行垂直投影和水平投影时,我们获得了一个数组,上面的每个元素是某一列或者某一行的白色像素点个数。
我们可以从垂直投影中,可以直观的看出每个字符的分割。
step2 对水平投影进行峰谷分析
算出水平投影的平均值,我们将这个平均值视为阈值,用于后面进行比对。
其计算公式为,(水平投影的平均值+最小值)/2
设置变量:
count1=0; %% 用于计数,统计当前峰或者谷的宽度
l=1; %% 用做索引,作为当前峰或谷的下标
hight=size(sbw1,1); %% 获取图像的高度
我将以代码为例一步一步解析,先处理水平投影
for k=1:hight
if histrow(k)<=levelrow
count1=count1+1;
else
if count1>=1
markrow(l)=k;%上升点
markrow1(l)=count1;%谷宽度(下降点至下一个上升点)
l=l+1;
end
count1=0;
end
end
可以看到当当前行投影小于我们设定的阈值时,另count1++,这是记录谷宽度,以下图为例,当前阈值为36,也就是直到k=5时才会进入else环节,可以看到若是中间没有宽度,则不会记录该点。
假设我们记录了改点,使用markrow数组记录上升点下标,使用markrow1数组记录对应上升点的谷宽度
markrow: 5,50
markrow1: 4, 0
markrow2: 45
markrow3: 50
markrow:4: 45
markrow:5: 27
markrow2数组存储各个上升点之间的谷宽度(各峰之间的距离),n1获得markrow2的长度。
最后补一个最后峰之间的距离。
markrow2=diff(markrow);%峰距离(上升点至下一个上升点)
[~,n1]=size(markrow2);
n1=n1+1;
markrow(l)=hight;
markrow1(l)=count1;
markrow2(n1)=markrow(l)-markrow(l-1);
% l=0;
markrow3记录谷宽度的起始点,也就是下降点
markrow4记录峰宽度,下降点与上升点之间的距离
markrow5记录各个峰中心位置,这里只有两个峰(上升点)所以只计算一个
for k=1:n1 %%n1是markrow2的长度
markrow3(k)=markrow(k+1)-markrow1(k+1);%下降点
markrow4(k)=markrow3(k)-markrow(k);%峰宽度(上升点至下降点)
markrow5(k)=markrow3(k)-double(uint16(markrow4(k)/2));%峰中心位置
end
%Step7 计算车牌旋转角度
%(1)在上升点至下降点找第一个为1的点
[m2,n2]=size(sbw1);%sbw1的图像大小
[m1,n1]=size(markrow4);%markrow4的大小
maxw=max(markrow4);%最大宽度为字符
if markrow4(1) ~= maxw % 检测上边
ysite = 1;
k1 = 1;
for l = 1:n2
for k = markrow3(ysite):m2 % 从顶边至第一个峰下降点扫描
if sbw1(k, l) == 1
xdata(k1) = l;
ydata(k1) = k;
k1 = k1 + 1;
break;
end
end
end
else %检测下边
ysite=n1;
if markrow4(n1) ==0
if markrow4(n1-1) ==maxw
ysite= 0; %无下边
else
ysite= n1-1;
end
end
if ysite ~=0
k1=1;
for l=1:n2
k=m2;
while k>=markrow(ysite) %从底边至最后一个峰的上升点扫描
if sbw1(k,l)==1
xdata(k1)=l;
ydata(k1)=k;
k1=k1+1;
break;
end
k=k-1;
end
end
end
end
· 这里我们需要理解的是,我们是从上往下一行一行的扫描,所以如果所给予的初始图片是车牌,那么,最大峰宽度所代表的就是车牌中的内容。
为了方便理解,我制作了一张图,次图中有两个峰,可以看到若不为最大峰宽度,他就不是车牌中的内容。
一般处理的图片是这样的
首先确定底边的位置,如果最后一个峰的宽度为 0,则说明无下边
然后从上边缘或者截止至下边缘起依次寻找每一列的第一个白色像素点位置。
%(2)线性拟合,计算与x夹角
fresult = fit(xdata',ydata','poly1'); %poly1 Y = p1*x+p2
p1=fresult.p1;
angle=atan(fresult.p1)*180/pi; %弧度换为度,360/2pi, pi=3.14 这个角度是怎么计算的
使用每列的第一个白色像素点的位置来拟合一条直线,获取直线斜率,然后计算斜率的反正切值,得到拟合直线与x轴的夹角。
sbw = imrotate(sbw1,angle,'bilinear','crop');%旋转图像
使用matlab中的imrotate函数,'bilinear'指定插值方法这里指定双线性插值方法,'crop'表示在旋转过程中会裁剪图片,使得裁剪后的图片和原图片大小相同。