粗网格单特征MNIST手写数字识别

  • 目的:通过单特征提取学习对手写数字进行识别
  • 工具:MatLab R2009b
  • 手写数字库:MNIST 手写数字库(60000训练样本、10000测试样本)
  • 特征:7×7粗网格
  • 识别率:80%

MNIST 手写数字库是~NEC~开发的,所有的手写数字样本都标准化到 28×28 像素大小的 bmp 图片。实验首先需要将下载的 MNIST 数据提取出 bmp 文件(样本)和 txt 文件(保存样本的正确数字值),程序下载(修改后缀名)。

实验分为两部分:识别训练(grid_study.m)、识别测试(recognition.m)

识别训练(grid_study.m)代码如下,study.txt 是所学习的 60000 个样本的正确值,首先依次读出训练样本,进行二值化处理,然后在 7×7 粗网格内计算每个粗网格内的黑色像素个数,计算每个方格黑色像素个数在样本图像中黑色像素的所占百分比作为特征值,在计算完 0-9 所有特征后写入到 features.txt 。

 1: clear;
 2: clc;
 3: directory=uigetdir('','亲,请选择学习图片路径');
 4: ImageNum=60000;
 5: numis=textread('study.txt','%1d'); %numis 是正确的ImageNum个样本值
 6: feasum=zeros(10,49); %10*49的特征之和数组
 7: numsum=zeros(10); %0-9的个数,0用10代替
 8: h_w=waitbar(0,'请稍后,正在处理中>;>>>>>>>');
 9: for i=1:ImageNum
 10:     impath=fullfile(directory,['TrainImage_' num2str(i,'%05d') '.bmp']);
 11:  rawim=imread(impath);
 12:     xx=find(rawim<;100);
 13:     rawim(xx)=0;
 14:  x=find(rawim>=100);
 15:     rawim(x)=255;
 16:  bwim=im2bw(rawim,0.5);%二值化
 17:
 18:     gridnum=zeros(1,49)         ;%保存49个块的黑色像素个数
 19:     xbase=1;
 20:  ybase=1;
 21:     for yz=0:6
 22:         for xz=0:6          %这两个是7*7的大块
 23:             for ybase=1:4
 24:                 for xbase=1:4       %这两个是在4*4的小块内
 25:                     if(bwim(yz*4+ybase,xz*4+xbase)==0)  %如果是黑色像素
 26:                         gridnum(yz*7+xz+1)=gridnum(yz*7+xz+1)+1;
 27:  end
 28:                 end
 29:             end
 30:         end
 31:     end
 32:
 33:     jud=numis(i);
 34:  if jud==0 %如果是0,放在第十个
 35:         jud=10;
 36:  end
 37:     numsum(jud)=numsum(jud)+1; %统计0-9的个数
 38:     for t=1:49
 39:         feasum(jud,t)=feasum(jud,t)+gridnum(t);
 40:  end
 41:     waitbar(i/ImageNum);
 42: end
 43: sum=zeros(10); %sum保存0-9所有节点黑色像素总和,用于归一化
 44: for i=1:10
 45:     for j=1:49
 46:         sum(i)=sum(i)+feasum(i,j);
 47:  end
 48: end
 49: feature=zeros(10,49);
 50: for i=1:10
 51:     for j=1:49
 52:         feature(i,j)=feasum(i,j)/sum(i);
 53:  end
 54: end
 55: fid=fopen('features.txt','w'); %将特征值写到 feature.txt 文件
 56: for i=1:10
 57:     for j=1:49
 58:         fprintf(fid,'%1.8f ',feature(i,j));
 59:  end
 60:     fprintf(fid,'\n');
 61: end
 62: fclose(fid);
 63: close(h_w);

识别测试(recognition.m)代码如下,test.txt 是所测试的 10000 个样本的正确值,对测试样本的处理和训练过程一样,计算每个图像的特征后与读取的特征 fea 相比较,计算测试样本特征与读取的十个数字的标准特征的欧式距离,如果样本特征与数字x 标准特征距离最小,那么认为样本数值为x ,把判断的结果和真实结果 test.txt 比较,如果正确则不记录,错误则在 log.txt 内记录,并在 estat 内保存所有数字的错误个数。

 1: clear;
 2: clc;
 3: directory=uigetdir('','亲,请选择测试图片路径《注意是测试集》');
 4: ImageNum=10000;
 5: numis=textread('test.txt','%1d'); %numis 是正确的ImageNum个样本值
 6: numsum=zeros(1,10); %0-9的个数,0用10代替
 7: errornum=0; %识别错误个数
 8: fid=fopen('log.txt','w');
 9: %读取学习来的特征值
 10: fea=load('features.txt'); %10*49的每个数字的特征数
 11: estat=zeros(1,10);
 12: h_w=waitbar(0,'请稍后,正在处理中>>>>>>>>');
 13: for i=1:ImageNum
 14:     impath=fullfile(directory,['TestImage_' num2str(i,'%05d') '.bmp']);
 15:  rawim=imread(impath);
 16:     xx=find(rawim<;155);
 17:     rawim(xx)=0;
 18:  x=find(rawim>=155);
 19:     rawim(x)=255;
 20:  bwim=im2bw(rawim,0.5);%二值化
 21:     %读取每个块的像素个数
 22:     gridnum=zeros(1,49); %保存49个块的黑色像素个数
 23:     xbase=1;
 24:  ybase=1;
 25:     for yz=0:6
 26:         for xz=0:6          %这两个是7*7的大块
 27:             for ybase=1:4
 28:                 for xbase=1:4       %这两个是在4*4的小块内
 29:                     if(bwim(yz*4+ybase,xz*4+xbase)==0)  %如果是黑色像素
 30:                         gridnum(yz*7+xz+1)=gridnum(yz*7+xz+1)+1;
 31:  end
 32:                 end
 33:             end
 34:         end
 35:     end
 36:     %统计49块中所有黑色像素并归一化
 37:     sum=0;
 38:  for c=1:49 
 39:         sum=sum+gridnum(c);
 40:  end
 41:     %每个格子像素个数归一化
 42:     numfea=zeros(1,49);
 43:  for c=1:49
 44:         numfea(c)=gridnum(c)/sum;
 45:  end
 46:     %计算距离
 47:     dist=zeros(1,10); %dist(c) 代表与标准第c个数字的距离
 48:     for c=1:10
 49:         for d=1:49
 50:             temp=numfea(d)-fea(c,d); %该数字第d块减去数字c第d块特征值
 51:             dist(c)=dist(c)+temp^2;
 52:  end
 53:     end
 54:     %计算最小距离和对应的index
 55:     [a,index]=min(dist);
 56:  %numis 标准值
 57:     jud=numis(i);
 58:  if jud==0 %如果是0,放在第十个
 59:         jud=10;
 60:  end
 61:     numsum(jud)=numsum(jud)+1; %统计0-9的个数
 62:     %比较index 和jud 相等否,相等识别正确,不相等识别错误并记录
 63:     if index~=jud
 64:         errornum=errornum+1;
 65:  if jud==10;
 66:             temp=0;
 67:  else
 68:             temp=jud;
 69:  end
 70:         if index==10;
 71:  tempi=0;
 72:         else
 73:             tempi=index;
 74:  end
 75:         estat(jud)=estat(jud)+1;
 76:  fprintf(fid,'%5dth misrecognize %d to %d\n',i,temp,tempi);
 77:     end
 78:     waitbar(i/ImageNum);
 79: end
 80: fclose(fid);
 81: close(h_w);

最后在 10000 个样本中错误识别了 2089 个数字,识别率约为 80% 。具体每个数字的识别如图(红线代表样本个数,蓝线代表误识个数):

ok

从图中看出数字 0 、1 和数字 3 有较好的识别率,但总体识别率不高,这是因为单特征具有局限性,如果加入其他特征会有更好的效果。全部文件:77grid.rar(修改后缀)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据