Chinaunix首页 | 论坛 | 博客
  • 博客访问: 873416
  • 博文数量: 372
  • 博客积分: 10063
  • 博客等级: 中将
  • 技术积分: 4220
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 11:36
文章分类

全部博文(372)

文章存档

2012年(372)

分类: 虚拟化

2012-03-07 16:38:00

离线手写数字识别系统设计主要分为3个部分:图像预处理、数字的分割、数字的识别。

1.图像预处理

图像预处理主要是指对输入的图像进行灰度化、滤波、二值化。

鉴于数字的识别与色彩无关,并且考虑到噪声的影响(这里采用中值滤波),将图像进行预处理。

1 clear all;
2 clc;
3 test=input('Please input a digits image:','s'); %输入图像
4 x=imread(test);
5 if ~isgray(x)
6 x=rgb2gray(x); %必须转换为灰度图像
7 end
8 xbw=im2bw(x,0.9); %再转换为二值图像
9 xbw=medfilt2(xbw); %中值滤波
10 bw=xbw; %滤波后二值图像
11
12 figure;imshow(bw);

2.图像切割(字符分离)

原理:

当图像转换为二值图像后,利用边界点确定单个字符(假设每个数字之间均存在空白、间隔),如下:

当需要提取‘4’这个字符的时候,需要在横向、纵向上确定字符的上下边界点。

这里需要用到函数find()和all()【find()结果为满足条件的所有值,all():所有的点均满足某条件的值】

先确定左边界,再找到全1列(右边红线),以此类推确定上下边界。

1 for n=1:100
2 [c,l]=size(bw);
3 [i,j] = find(bw==0);
4 jmin1=min(j);
5 xbwt=bw(:,jmin1:l); %xbwt为切除左边边缘的图像
6 [c,l]=size(xbwt);
7 [i,j]=find(all(xbwt(1:c,:)==1));
8 jmin2=min(j); %找右边界
9 if(isempty(jmin1)||isempty(jmin2)) break;
10 end
11 xbwn{n}=xbwt(:,1:jmin2-1); %xbwn{n+1}为第(n+1)个数字图像
12 bw=xbwt(:,jmin2:l); %bw迭代循环使用
13 [i,j] = find(xbwn{n}==0); %找上下边界
14 imin=min(i);
15 imax=max(i); %imin:数字最上点,imax:数字最下点
16 xbwn1{n}=xbwn{n}(imin:imax,:);
17
18 end

如上图所示数字太过饱满,需要骨架化一下才能方便识别,这里需要用到matlab的bwmorph()函数,详见http://www.mathworks.cn/help/toolbox/images/ref/bwmorph.html

1 m=n-1;
2 for n=2:m
3 [i,j]=size(xbwn1{n});
4 p=-1.*xbwn1{n}+ones(i,j); %先将矩阵取反
5 xbwn2{n}=bwmorph(p,'skel',Inf);
6 %figure,imshow(xbwn2{n});
7 end

3.字符的匹配识别

1)统一标准

将提取出来的字符图片大小全部统一为16X16

2)提取特征向量

特征向量x为由以下数据组成的数组,

x1:数字的端点数(8邻域内黑点数目为3(包括本身)),

x2:数字一般连接点(字轨迹长度),

x3:数字分叉点(8邻域内黑点数目大于3(包括本身)),

x4~x19:16条水平线分别与数字的交点个数,

x20~x35:16条垂直线分别与数字的交点个数 。

3)匹配确定数字

假设标准数字(0~9)的特征向量已知为y,则匹配的准则为计算x和y的相似度r.

r=Σ(xi*yi)/sqrt(Σ(xi^2)*Σ(yi^2));【sqrt为平方根运算】


r数字越接近于1,表明y和x越相似,即未知字符最有可能为y对应的标准数字。

下面是matlab代码:

solve.m

1 function x=solve(ju)
2 x=zeros(1,35);
3 [m,n]=size(ju);
4 ju1=zeros(m+2,n+2);
5 ju1(2:m+1,2:n+1)=ju(:,:);
6 for i=2:m+1
7 for j=2:n+1
8 if ju1(i,j)==1
9 temp=ju1(i-1:i+1,j-1:j+1);%邻域矩阵
10 [ii,jj]=find(temp==1);
11 if max(size(ii))>=4
12 x(3)=x(3)+1;
13 else if max(size(ii))==3
14 x(2)=x(2)+1;
15 else
16 x(1)=x(1)+1;
17 end
18 end
19 x(i+3)=x(i+3)+1;
20 x(j+19)=x(j+19)+1;
21 end
22 end
23 end

值得注意的是,上面第5行用ju1代替ju,是为了方便判断边缘上的点(ju此时寻找8邻域会出错),所以在四周加上了无关‘边’。

pipei.m

1 function result=pipei(a,j)
2 sta=[0 27 5 0 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 0 0 0 0 0 11 5 2 2 3 9 0 0 0 0
3 2 14 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 15 1 0 0 0 0 0 0
4 2 18 3 0 0 0 3 2 2 1 1 1 1 1 1 1 1 1 5 2 0 0 0 0 0 6 4 3 3 4 3 0 0 0 0
5 3 18 4 0 0 3 2 1 1 1 1 4 1 1 1 2 2 2 3 0 0 0 0 0 0 1 3 3 3 3 9 3 0 0 0
6 3 20 6 0 1 1 1 1 2 2 2 2 2 2 2 2 6 1 1 1 0 0 0 0 0 4 4 2 4 13 1 1 0 0 0
7 3 23 3 0 5 1 1 1 1 4 2 2 1 1 1 2 2 2 3 0 0 0 0 0 0 6 4 3 3 3 9 1 0 0 0
8 1 24 4 0 0 3 2 1 1 1 5 2 2 2 2 2 2 2 2 0 0 0 0 0 0 11 3 3 3 4 5 0 0 0 0
9 2 17 3 0 6 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 5 6 4 4 1 0 0 0
10 0 23 13 0 1 4 2 2 2 2 2 4 2 2 2 2 2 2 4 1 0 0 0 0 0 8 8 3 3 6 8 0 0 0 0
11 1 28 4 0 0 4 2 2 2 2 2 2 2 3 3 1 2 2 4 0 0 0 0 0 0 9 3 3 3 3 12 0 0 0 0];
12 sx2=0;sy2=0;sxy=0;
13 for i=1:35
14 sx2=sx2+a(i)*a(i);
15 sy2=sy2+sta(j,i)*sta(j,i);
16 sxy=sxy+a(i)*sta(j,i);
17 end
18 result=sxy/sqrt(sx2*sy2);
19

上面的sta数据为测试所得,由于标准有异,读者可以自己收集数据,调试。

完整的主程序如下:

View Code
1 clear all;
2 clc;
3 test=input('Please input a digits image:','s'); %输入图像
4 %z=input('z:','s');
5 x=imread(test);
6 if ~isgray(x)
7 x=rgb2gray(x); %必须转换为灰度图像
8 end
9 xbw=im2bw(x,0.9); %再转换为二值图像
10 xbw=medfilt2(xbw); %中值滤波
11 bw=xbw; %滤波后二值图像
12
13 figure;imshow(bw);
14
15 for n=1:100
16 [c,l]=size(bw);
17 [i,j] = find(bw==0);
18 jmin1=min(j);
19 xbwt=bw(:,jmin1:l); %xbwt为切除左边边缘的图像
20 [c,l]=size(xbwt);
21 [i,j]=find(all(xbwt(1:c,:)==1));
22 jmin2=min(j); %找右边界
23 if(isempty(jmin1)||isempty(jmin2)) break;
24 end
25 xbwn{n}=xbwt(:,1:jmin2-1); %xbwn{n+1}为第(n+1)个数字图像
26 bw=xbwt(:,jmin2:l); %bw迭代循环使用
27 [i,j] = find(xbwn{n}==0); %找上下边界
28 imin=min(i);
29 imax=max(i); %imin:数字最上点,imax:数字最下点
30 xbwn1{n}=xbwn{n}(imin:imax,:);
31
32 end
33 m=n-1;
34 for n=2:m
35 [i,j]=size(xbwn1{n});
36 p=-1.*xbwn1{n}+ones(i,j); %先将矩阵取反
37 x=16;
38 p1=ones(x,x);
39 %xbwn2{n}=bwmorph(p,'skel',Inf);
40 xbwn2{n}=xbwn1{n};
41 %转换到x*x矩阵
42 rate=x/max(size(xbwn2{n}));
43 xbwn3{n}=imresize(xbwn2{n},rate);
44 [i,j]=size(xbwn3{n});
45 i1=round((x-i)/2);
46 j1=round((x-j)/2);
47 p1(i1+1:i1+i,j1+1:j1+j)=xbwn3{n};
48 p1=ones(x,x)-p1;
49 p1=bwmorph(p1,'skel',Inf);
50 p2{n}=p1;
51
52 temp1=solve(p1);
53 temp2=0;
54 temp_index=0;
55 for tt=1:10
56 temp3=pipei(temp1,tt);
57 if temp3>temp2
58 temp2=temp3;
59 temp_index=tt-1;
60 end
61 end
62 temp_index %显示数字
63
64 figure,imshow(p1);
65 end

参考论文:

基于图像识别技术的手写数字识别方法 吴忠1,2,朱国龙1,2,黄葛峰1,2,吴建国1,2

需要完善的地方:

1.评判机制

可以适当调整x1~x3等的权系数,使得相似度测量更精确;

2.标准手写字体的数据收集

本实验只是找了一个印刷体的数据得到了sta数组;

3.字符的分割

中值滤波不一定能很好的滤去一些端状杂质,需要根据高度和宽度大小限制再进一步滤波。

最后,有不当之处,希望园友指正。

转载请注明:http://www.cnblogs.com/blue-lg/archive/2012/03/05/2381078.html

阅读(1126) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~