%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 字符分割模块算法 % 定位剪切后的彩色车牌图像--灰度--二值化--统一到黑底白字--去除上下边框 % --切割出最小范围--滤波--形态学处理--分割出7个字符 % 去除上下边框算法: % 1.黑白跳变小于阈值则被视为背景;2.连续白线大于某阈值则该白线被认为是背景 % 3.单行白色大于阈值则被认为是背景,考虑FLAG的值; % 4.做完以上处理后,上边1/2 中搜索连续两条黑线,认为该黑线以上为背景;在下边1/2 中搜索连续两条黑线,认为该黑线以下为背景 % 归一化为 40*20 ,商用系统程序中归一化为 32*16 ,此处仅演示作用 function [d]=lpcseg(jpg) I=imread('car1.jpg'); I1=rgb2gray(I); I2=edge(I1,'robert',0.15,'both'); se=[1;1;1]; I3=imerode(I2,se); se=strel('rectangle',[25,25]); I4=imclose(I3,se); I5=bwareaopen(I4,2000); [y,x,z]=size(I5); myI=double(I5); tic 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); PY1=MaxY; while ((white_y(PY1,1)>=5)&&(PY1>1)) PY1=PY1-1; end PY2=MaxY; while ((white_y(PY2,1)>=5)&&(PY2<y)) PY2=PY2+1; end IY=I(PY1:PY2,:,:); white_x=zeros(1,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; while ((white_x(1,PX1)<3)&&(PX1<x)) PX1=PX1+1; end PX2=x; while ((white_x(1,PX2)<3)&&(PX2>PX1)) PX2=PX2-1; end PX1=PX1-1; PX2=PX2+1; dw=I(PY1:PY2-8,PX1:PX2,:); t=toc; figure(1),subplot(3,2,1),imshow(dw),title('定位剪切后的彩色车牌图像') imwrite(dw,'dw.jpg'); [filename,filepath]=uigetfile('dw.jpg','输入一个定位裁剪后的车牌图像'); jpg=strcat(filepath,filename); a=imread(jpg); %figure(1);subplot(3,2,1),imshow(a),title('1.定位剪切后的彩色车牌图像') b=rgb2gray(a); imwrite(b,'2.车牌灰度图像.jpg'); figure(1);subplot(3,2,2),imshow(b),title('2.车牌灰度图像') g_max=double(max(max(b))); g_min=double(min(min(b))); T=round(g_max-(g_max-g_min)/3); % T 为二值化的阈值 [m,n]=size(b); d=(double(b)>=T); % d:二值图像 imwrite(d,'3.车牌二值图像.jpg'); figure(1);subplot(3,2,3),imshow(d),title('3.车牌二值图像') % 旋转 rotate=0; d=imread('3.车牌二值图像.jpg'); bw=edge(d); [m,n]=size(d); theta=1:179; % bw 表示需要变换的图像,theta 表示变换的角度 % 返回值 r 表示的列中包含了对应于 theta中每一个角度的 Radon 变换结果 % 向量 xp 包含相应的沿 x轴的坐标 [r,xp]=radon(bw,theta); i=find(r>0); [foo,ind]=sort(-r(i)); k=i(ind(1:size(i))); [y,x]=ind2sub(size(r),k); [mm,nn]=size(x); if mm~=0 && nn~=0 j=1; while mm~=1 && j<180 && nn~=0 i=find(r>j); [foo,ind]=sort(-r(i)); k=i(ind(1:size(i))); [y,x]=ind2sub(size(r),k); [mm,nn]=size(x); j=j+1; end if nn~=0 if x % Enpty matrix: 0-by-1 when x is an enpty array. x=x; else % 可能 x 为空值 x=90; % 其实就是不旋转 end d=imrotate(d,abs(90-x)); % 旋转图像 rotate=1; end end imwrite(d,'4.Radon 变换旋转后的二值图像.jpg'); figure(1),subplot(3,2,4),imshow(d),title('4.Radon 变换旋转后的二值图像') % 统一到白底黑字 [m,n]=size(d); % flag=0 表示原来就是白底黑字,否则表示原来是黑底白字 flag=0; c=d([round(m/3):m-round(m/3)],[round(n/3):n-round(n/3)]); if sum(sum(c))/m/n*9>0.5 d=~d;flag=1; end % 对反色后的图像预处理,整列几乎为白的认为是背景 if flag==1 for j=1:n if sum(sum(d(:,j)))/m>=0.95 d(:,j)=0; end end % 对以上处理后的图像再处理 % 在左边 1/2 处找连续两条黑线,认为该黑线左边为背景;在右边 1/2 处找连续两条黑线,认为该黑线右边是背景 % 左边 1/2 jj=0; for j=1:round(n/2) if sum(sum(d(:,[j:j+0])))==0 jj=j; end end d(:,[1:jj])=0; % 右边 1/2 for j=n:-1:round(n/2) if sum(sum(d(:,[j-0:j])))==0 jj=j; end end d(:,[jj:n])=0; end imwrite(d,'5.统一成黑底白字.jpg'); figure(1),subplot(3,2,5),imshow(d),title('5.背景色统一成黑底白字') figure(2),subplot(5,1,1),imshow(d),title('5.黑底白字的二值车牌图像') % 去除上下边框 % STEP 1 黑白跳变小于阈值则被视为背景 % 上面 2/5 y1=10; % y1: 跳变阈值 for i=1:round(m/5*2) count=0;jump=0;temp=0; for j=1:n if d(i,j)==1 temp=1; else temp=0; end if temp==jump count=count; else count=count+1; end jump=temp; end if count<y1 d(i,:)=0; end end % 下面 2/5 for i=3*round(m/5):m count=0;jump=0;temp=0; for j=1:n if d(i,j)==1 temp=1; else temp=0; end if temp==jump count=count; else count=count+1; end jump=temp; end if count<y1 d(i,:)=0; end end imwrite(d,'6.黑白跳变小于某阈值的行则被视为背景.jpg'); figure(2),subplot(5,1,2),imshow(d),title('6.黑白跳变小于某阈值的行则被视为背景') % STEP 2 单行白色大于阈值则被认为是背景,考虑 FLAG 的值 % 上面 2/5 y2=round(n/2); % y2: 阈值 for i=1:round(m/5*2) if flag==0 temp=sum(d(i,:));y2=round(n/2); if temp>y2 d(i,:)=0; end else temp=m-sum(d(i,:));y2=m-round(n/2); if temp<y2 d(i,:)=0; end end end % 下面 2/5 for i=round(3*m/5):m if flag==0 temp=sum(d(i,:));y2=round(n/2); if temp>y2 d(i,:)=0; end else temp=m-sum(d(i,:));y2=m-round(n/2); if temp<y2 d(i,:)=0; end end end imwrite(d,'7.单行白色点总数大于某阈值则该行被认为是背景.jpg'); figure(2),subplot(5,1,3),imshow(d),title('7.单行白色点总数大于某阈值则该行被认为是背景') % STEP 3 单行白色大于阈值则被认为是背景,考虑 FLAG 的值 % 上面 2/5 y2=round(n/2); % y2: 阈值 for i=1:round(m/5*2) if flag==0 temp=sum(d(i,:));y2=round(n/2); if temp>y2 d(i,:)=0; end else temp=m-sum(d(i,:));y2=m-round(n/2); if temp<y2 d(i,:)=0; end end end % 下面 2/5 for i=round(3*m/5):m if flag==0 temp=sum(d(i,:));y2=round(n/2); if temp>y2 d(i,:)=0; end else temp=m-sum(d(i,:));y2=m-round(n/2); if temp<y2 d(i,:)=0; end end end imwrite(d,'8.单行白色点总数大于某阈值则该行被认为是背景.jpg'); figure(2),subplot(5,1,4),imshow(d),title('8.单行白色点总数大于某阈值则该行被认为是背景') % STEP 4 做完以上处理后,上边 1/2 中搜索连续两条黑线,认为该黑线以上为背景; % 在下边 1/2 中搜索连续两条黑线,认为该黑线以下为背景 % 上边 1/2 for i=1:round(m/2) if sum(sum(d([i,i+0],:)))==0 ii=i; end end d([1:ii],:)=0; % 下边 1/2 for i=m:-1:round(m/2) if sum(sum(d([i-0:i],:)))==0 ii=i; end end d([ii:m],:)=0; imwrite(d,'9.搜索上下两条黑线后的结果.jpg'); figure(2),subplot(5,1,5),imshow(d),title('9.搜索上下两条黑线后的结果') % 反旋转 if rotate==1 d=imrotate(d,-abs(x-90)); end imwrite(d,'10.反旋转去毛刺后.jpg'); figure(3),subplot(3,2,1),imshow(d),title('10.反旋转去毛刺后') % 切割处最小范围 d=qiege(d);e=d; imwrite(d,'11.切割处最小范围.jpg'); figure(3),subplot(3,2,2),imshow(d),title('11.切割处最小范围') figure(3),subplot(3,2,3),imshow(d),title('11.均值滤波前') % 滤波 h=fspecial('average',3); d=im2bw(round(filter2(h,d))); imwrite(d,'12.均值滤波后.jpg'); figure(3),subplot(3,2,4),imshow(d),title('12.均值滤波后') % 某些图像进行操作 % 膨胀或腐蚀 % se=strel('square',3); % 使用一个3X3的正方形结果元素对象对创建的图像进行膨胀 % 'line'/'diamond'/'ball'... se=eye(2); % eye(n) returns the n-by-n identity matrix 单位矩阵 [m,n]=size(d); if bwarea(d)/m/n>=0.365 d=imerode(d,se); elseif bwarea(d)/m/n<=0.235 d=imdilate(d,se); end imwrite(d,'13.膨胀或腐蚀处理后.jpg'); figure(3),subplot(3,2,5),imshow(d),title('13.膨胀或腐蚀处理后') % 寻找连续有文字的块,若长度大于某阈值,则认为该块有两个字符组成,需要分割 d=qiege(d); [m,n]=size(d); figure,subplot(2,1,1),imshow(d),title(n) k1=1;k2=1;s=sum(d);j=1; while j~=n while s(j)==0 j=j+1; end k1=j; while s(j)~=0 && j<=n-1 j=j+1; end k2=j-1; if k2-k1>=round(n/6.5) [val,num]=min(sum(d(:,[k1+5:k2-5]))); d(:,k1+num+5)=0; % 分割 end end % 再切割 d=qiege(d); % 切割出 7 个字符 y1=10;y2=0.25;flag=0;word1=[]; while flag==0 [m,n]=size(d); left=1;wide=0; while sum(d(:,wide+1))~=0 wide=wide+1; end if wide<y1 % 认为是左侧干扰 d(:,[1:wide])=0; d=qiege(d); else temp=qiege(imcrop(d,[1 1 wide m])); [m,n]=size(temp); all=sum(sum(temp)); two_thirds=sum(sum(temp([round(m/3):2*round(m/3)],:))); if two_thirds/all>y2 flag=1;word1=temp; % WORD 1 end d(:,[1:wide])=0;d=qiege(d); end end % 分割出第二个字符 [word2,d]=getword(d); % 分割出第三个字符 [word3,d]=getword(d); % 分割出第四个字符 [word4,d]=getword(d); % 分割出第五个字符 [word5,d]=getword(d); % 分割出第六个字符 [word6,d]=getword(d); % 分割出第七个字符 [word7,d]=getword(d); subplot(5,7,1),imshow(word1),title('1'); subplot(5,7,2),imshow(word2),title('2'); subplot(5,7,3),imshow(word3),title('3'); subplot(5,7,4),imshow(word4),title('4'); subplot(5,7,5),imshow(word5),title('5'); subplot(5,7,6),imshow(word6),title('6'); subplot(5,7,7),imshow(word7),title('7'); [m,n]=size(word1); % 商用系统程序中归一化大小为 32*16,此处演示 word1=imresize(word1,[40 20]); word2=wordprocess(word2); word3=wordprocess(word3); word4=wordprocess(word4); word5=wordprocess(word5); word6=wordprocess(word6); word7=wordprocess(word7); subplot(5,7,15),imshow(word1),title('1'); subplot(5,7,16),imshow(word2),title('2'); subplot(5,7,17),imshow(word3),title('3'); subplot(5,7,18),imshow(word4),title('4'); subplot(5,7,19),imshow(word5),title('5'); subplot(5,7,20),imshow(word6),title('6'); subplot(5,7,21),imshow(word7),title('7'); imwrite(word1,'14.字符分割归一化后 1.jpg'); imwrite(word2,'14.字符分割归一化后 2.jpg'); imwrite(word3,'14.字符分割归一化后 3.jpg'); imwrite(word4,'14.字符分割归一化后 4.jpg'); imwrite(word5,'14.字符分割归一化后 5.jpg'); imwrite(word6,'14.字符分割归一化后 6.jpg'); imwrite(word7,'14.字符分割归一化后 7.jpg'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% clc word=''; word(1)=wordrec(word1); word(2)=wordrec(word2); word(3)=wordrec(word3); word(4)=wordrec(word4); word(5)=wordrec(word5); word(6)=wordrec(word6); word(7)=wordrec(word7); clc save I 'word1' 'word2' 'word3' 'word4' 'word5' 'word6' 'word7' clear load I; load bp net; word=''; word(1)=wordrec(word1); word(2)=wordrec(word2); word(3)=wordrec(word3); word(4)=wordrec(word4); word(5)=wordrec(word5); word(6)=wordrec(word6); word(7)=wordrec(word7); word=strcat('识别结果:',word); subplot(5,3,14),imshow([]),title(word,'fontsize',24) % 该子程序用于切割出最小范围 function e=qiege(d) [m,n]=size(d); top=1;bottom=m;left=1;right=n; % init 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]); % 分割字符 function [word,result]=getword(d) word=[];flag=0;y1=8;y2=0.5; % if d==[] % word=[]; % else while flag==0 [m,n]=size(d); wide=0; while sum(d(:,wide+1))~=0 && wide<=n-2 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 %end result=d; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 该子程序用于字符归一化处理 function d=wordprocess(d) [m,n]=size(d); %top 1/3, bottom 1/3 for i=1:round(m/3) if sum(sum(d([i:i+0],:)))==0 ii=i;d([1:ii],:)=0; end end for i=m:-1:2*round(m/3) if sum(sum(d([i-0:i],:)))==0 ii=i;d([ii:m],:)=0; end end if n~=1 d=qiege(d); end % d=..这个可以通过训练过程设置大小 % d=imresize(d,[32 16]); % 商用系统程序中归一划大小为:32*16 d=imresize(d,[40 20]); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 编号:A-Z 分别为 1-26; 0-9 分别为 27-36; % 京 津 沪 渝 港 澳 吉 辽 鲁 豫 冀 鄂 湘 晋 青 皖 苏 % 赣 浙 闽 粤 琼 台 陕 甘 云 川 贵 黑 藏 蒙 桂 新 宁 % 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 % 60 61 62 63 64 65 66 67 68 69 70 % 使用 BP 网络 function word=wordrec(xx) % clear % clc load bp net; xx=im2bw(xx);xx=double(xx(:)); % 使用阈值将图像转换为二进制图像 a=sim(net,xx); % 归一划为: 32*16,则 xx=512*1; [val,num]=max(a); if num<=26 word=char(double('A')+num-1); elseif num<=36 word=char(double('0')+num-1-26); else switch num case 37 word='京'; case 38 word='津'; case 39 word='沪'; case 40 word='渝'; case 41 word='港'; case 42 word='澳'; case 43 word='吉'; case 44 word='辽'; case 45 word='鲁'; case 46 word='豫'; case 47 word='冀'; case 48 word='鄂'; case 49 word='湘'; case 50 word='晋'; case 51 word='青'; case 52 word='皖'; case 53 word='苏'; case 54 word='赣'; case 55 word='浙'; case 56 word='闽'; case 57 word='粤'; case 58 word='琼'; case 59 word='台'; case 60 word='陕'; case 61 word='甘'; case 62 word='云'; case 63 word='川'; case 64 word='贵'; case 65 word='黑'; case 66 word='藏'; case 67 word='蒙'; case 68 word='桂'; case 69 word='新'; case 70 word='宁'; end end