基於matlab的藍色車牌定位與識別---分割


     接着上面的工作,接下去就該是進行字符分割了。考慮到為了后面的字符識別,因此在這部分需要實現的目標是需要把車牌的邊框全部切除,對重新定位的車牌進行垂直方向水平方向調整,保證字符是正的。最后才是字符的分割。

     1.首先上下邊框切割。對定位的車牌每行作一次的差分,計算每行的綜合,小於某個閾值時候將其舍去。部分代碼:

[length height]=size(p);
% 水平方向定位
for i=1:length % 水平一階差分
    for j=1:height-1
        revise_row(i,j)=abs(p(i,j)-p(i,j+1));
    end   
     revise_row(i,height)=revise_row(i,height-1);
end
for i=1:length
      T(i)=sum(revise_row(i,:));
end   
for i=2:length-1
      T(i)=1/2*(T(i-1)+T(i)+T(i+1));
end   

T(1)= T(2);
T(length)=T(length-1);

% 截取水平區間
left_row=0;right_row=0;
threshold_row=max(T);
for i=1:length
     if(T(i)>1/6*threshold_row)
         left_row=i;
        break;
     end
end 
for i=length:-1:1
     if(T(i)>1/6*threshold_row)
          right_row=i;
        break;
     end
end 
temp=1;
 for i=left_row:right_row %截取區間
     p_row(temp,:)=p1(i,:); 
     temp=temp+1;
end 

  左右切割結果圖:

                                                                        

2  左右邊框切割。對定位的車牌每列作一次的差分。考慮到左右邊框的一階總數是兩邊大,中間小,因此采用獲取左右的峰值,當小於峰值的摸個閾值時進行截取。  部分代碼:

% 豎直方向定位
for j=1:height % 一階差分
    for i=1:length-1
        revise_column(i,j)=abs(p1(i,j)-p1(i+1,j));
    end   
    revise_column(length,j)=0;
end

for j=1:height
      T(j)=sum(revise_column(:,j));
end   
for j=2:height-1
      T(j)=1/3*(T(j-1)+T(j)+T(j+1));
end   
 T(1)= T(2);
 T(height)=T(height-1);
 [max_peak max_num]=max(T);%求出峰值
 threshold=0.25*max_peak;%閾值
 left_peak= T(1);
 right_peak= T(height);
 
 
 %找到左峰值
 for j=2:height 
      if(T(j)>=threshold&(T(j)>=T(j-1))&(T(j)>=T(j+1))&(j<=max_num))
       left_peak=j;
       break;
      end
 end   
 %找到右峰值
 if(max_num<1/2*height)
     threshold=1/2*threshold;
 end
 for j=height-1:-1:2
      if(T(j)>=threshold&(T(j)>=T(j-1))&(T(j)>=T(j+1))&(j>=max_num))
       right_peak=j;
        break;
      end
 end   
 left_valley=1;%谷底值
  right_valley=right_peak;
%找出左邊最小值
for j=left_peak:-1:2
      if((T(j)<=T(j-1))&(T(j)<=T(j+1)))
      left_valley=j;
          break;
      end
end   
 for j=right_peak:height-1
      if((T(j)<=T(j-1))&(T(j)<=T(j+1)))
       right_valley=j;
       break;
      end
 end   
 temp=1;
 for j=left_valley:right_valley  %截取部分參數分開,否則仍然按照原圖大小
      p_array(:,temp)=p_row(:,j);
      temp=temp+1;
 end

     截取圖:                                        

3 接下來進行車牌的水平校正。matlab里面有現成的函數imrotate,在-20~20角度范圍對車牌進行操作,完成水平校正。代碼

  

%水平校正
max_total=0;
sum_abs_angle=zeros(1,41);
count=1;
for  angle=-20:0.1:20%旋轉角度選擇
     p_array_temp=edge(p_array,'sobel','horizontal');%水平邊緣檢測
picbw_temp = imrotate(p_array,angle, 'bicubic','loose');%p_array對灰度圖像進行判斷操作
sum_xz=sum(picbw_temp'); %計算垂直投影
[sum_hight sum_width]=size(sum_xz);
%  figure,bar(sum_xz);title('垂直投影(含邊框)');%輸出垂直投影
% title(['車牌旋轉角: ',num2str(angle),'度后圖像'] ,'Color','r');%顯示車牌的旋轉角度
total_xz=0;
for i=1:sum_width-1
    total_xz=total_xz+abs(sum_xz(i)-sum_xz(i+1));   
end
if total_xz>max_total %找出一階導最大值
   angle_xz=angle;%調整角度
   picbw_xz=picbw_temp;
   max_total=total_xz;
end
sum_abs_angle(count)=total_xz;
count=count+1;
end 
%  figure,bar(sum_abs_angle);title('每個角度絕對值總和');%輸出垂直投影
image_correct=imrotate(p_array,angle_xz,'bicubic','loose');%車牌的水平旋轉校正
figure,imshow(mat2gray(image_correct));
 title(['車牌旋轉角: ',num2str(angle_xz),'度后圖像'] ,'Color','r');%顯示車牌的旋轉角度

  水平矯正結果:                       

    4  水平矯正后,我們還需要對車牌上下邊框再次進行切割,去除車牌上下邊框。與前面直接做一階差分不同,這里考慮到上下邊框水平成分較明顯,所以我們在這里先對車牌進行豎直方向的邊沿檢測,然后計算水平方向的均值進行切割。 部分代碼:

%去除上下邊框
max_num=max(max(image_correct));
min_num=min(min(image_correct));
thresh=(max_num-min_num)/5;%15
image_correct_row=edge(image_correct,'sobel',thresh,'vertical');%根據所指定的敏感度閾值thresh,在所指定的方向direction上,
% figure,imshow(image_correct_row);
title('豎直邊緣檢測');%顯示車牌的旋轉角度
histrow=sum(image_correct_row');  %計算水平投影
histrow_mean=mean(histrow);
histcol=sum(image_correct_row);  %計算豎直投影
histcol_mean=mean(histcol);
[width hight]=size(image_correct_row);
rowtop=0;
for i=1:width/2
    if histrow(i)>=1/3*histrow_mean & histrow(i+1)>1/2*histrow_mean & histrow(i+2)>1/2*histrow_mean & histrow(i+3)>1/2*histrow_mean  %連續有值判斷為上邊界
        rowtop=i; %上邊切割
        break;
    end
end
rowbot=0;
for i=width:-1:width/2
   if histrow(i)>=1/4*histrow_mean & histrow(i-1)>histrow_mean & histrow(i-2)>histrow_mean  & histrow(i-3)>histrow_mean & histrow(i-4)>histrow_mean
        rowbot=i; %下邊切割
        break;
    end
end

    結果圖:

                               

  可以看到,上下邊框基本清除,下面就需要對字符進行垂直校正。

    5   關於字符垂直校正,這個部分自己也沒太明白,只是參考別人的程序,可以交流。代碼:

 

max_total=0;
angle_yz=0;
sum_abs_angle=zeros(1,41);
count=1;
for  angle=-10:0.05:10%旋轉角度選擇
picbw_temp = imrotate(image_correct_x,angle, 'bicubic','crop');%p_array對灰度圖像進行判斷操作
sum_yz=sum(picbw_temp); %計算垂直投影
[sum_hight sum_width]=size(sum_yz);
total_yz=0;
for i=1:sum_width-1
    total_yz=total_yz+abs(sum_yz(i)-sum_yz(i+1));   
end
if total_yz>max_total %找出一階導最大值
   angle_yz=angle;
   picbw_yz=picbw_temp;
   max_total=total_yz;
end
sum_abs_angle(count)=total_yz;
count=count+1;
end 
Td=maketform('affine',[1 tand(angle_yz) 0;0 1 0;0 0 1]');%切變的參數結構體
image_correct_x_y=imtransform(image_correct_x,Td,'FillValues',255);%實現圖像切變

實驗結果:      

  6 這樣基本要做的都已經完成,剩下字符切割。在測試過程中,發現車牌的上下邊框邊角好去除,左右邊框則無法達到理想的要求,經常是要么沒有切割完全,要把把車牌字符也切割了。最后索性就不管左右邊框了,直接進行字符分割。自己所用的方法是:設置字符寬為width=1/2*車牌的高度;考慮到車牌的第二位和第三位之間有小點(也可能沒有),中間距離更大,所以認為車牌寬度的一半既是第四個字符所在位置或者是第三和第四字符之間,這里最主要是要確定某個參數,來標定車牌位置,便於分割。(實驗證明還是有效的)當遇到字符寬度大於默認width時,取大的值。車牌左右第一個和第七個字符則是截取默認寬度,去除邊框影響。部分代碼:

  獲取第四個字符:

%切割字符
[image_heigth image_length]=size(image_correct_x_y);
character_left=0;%切割字符左右位置
character_right=0;
middle_histcol=uint8(image_length/2);
char_width=image_heigth/2;%默認字符寬度

if binary_histcol(middle_histcol)>0 %垂直投影不為零
    %找出車牌的第四個字符
    for i=middle_histcol:-1:1 %字符左側
        if binary_histcol(i)==0
            character_left=i+1;
            break;
        end
    end
     for i=middle_histcol:image_length%字符右側
        if binary_histcol(i)==0
            character_right=i-1;
            break;
        end
     end
     result_char_forth(:,:)=binary_image(:,character_left:character_right);
else %認為中間值在 第三、四個字符之間
    for i=middle_histcol:image_length%獲取第四個字符
        if binary_histcol(i)>0 & binary_histcol(i-1)==0 %字符左起點
            character_left=i;
        end
        if binary_histcol(i)>0 & binary_histcol(i+1)==0 %字符右邊界
            character_right=i;
            break;
        end
    end
   result_char_forth(:,:)=binary_image(:,character_left:character_right); %獲取字符
   if character_right-character_left+1>char_width %比默認字符大
       char_width=character_right-character_left+1;%默認字符用於確認車牌左右兩側的寬度
   end
end

    判斷中間有無小點:

 %判斷有無中間小點!!!!! width_dot=4
 width_dot=4;%只能是字母,認為寬度小於4即為點,否則認為沒有點
 for i=current_left_position-1:-1:2
        if binary_histcol(i)>0 & binary_histcol(i+1)==0 %字符右起點
            character_right_temp=i;
        end
        if binary_histcol(i)>0 & binary_histcol(i-1)==0 %字符左邊界
            character_left_temp=i;
            break;
        end
 end
 if((character_right_temp-character_left_temp)>width_dot)%不是點
        current_left_position=character_left;%記錄當前位置放到下面讀取
 else %是點
      current_left_position=character_left_temp;%記錄當前位置
 end

  切割結果:

    可以看到,基本上消除了左右邊框的影響。七個工作基本完成!歡迎交流!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM