• 手写数字识别实现

设计技术参数:通过由数字构成的图像,自动实现几个不同数字的识别,设计识别方法,有较高的识别率

关键字:二值化  投影  矩阵  目标定位  Matlab

手写数字图像识别简介

手写阿拉伯数字识别是图像内容识别中较为简单的一个应用领域,原因有被识别的模式数较少(只有0到9,10个阿拉伯数字)、阿拉伯数字笔画少并且简单等。手写阿拉伯数字的识别采用的方法相对于人脸识别、汉字识别等应用领域来说可以采用更为灵活的方法,例如基于规则的方法、基于有限状态自动机的方法、基于统计的方法和基于神经网络的方法等。本文的开始部分先对手写阿拉伯数字识别的整个处理流程进行论述,而这个流程也可以用于图像中其他模式的识别。当然这个处理流程也不是唯一的,可以根据不同的模式识别应用场景进行与之不同的预处理流程。

手写数字图像识别的主要流程

第一步:对源图像进行黑白二值化处理;0数字的二值化(左)和1的二值化处理(右)

第二步:将图像在水平方向上和竖直方向上进行投影,这样通过投影图形就可以区分1和0的特征;

第三步:用投影计算出区域的横纵坐标,将其分为九份。定位出数字所在图像中的位置,提取该部分进行分析。

第四步:数字0和1的特征比较与识别

在0和一的比较中发现,在分成的九个区域的中间区域,0中间区域灰度为0,1中间区域灰度为1。

  • 人工神经网络

人类之所以能够思考,学习,判断,大部分都要归功于人脑中复杂的神经网络。虽然现在人脑的机理还没有完全破译,但是人脑中神经元之间的连接,信息的传递都已为人所知晓。于是人们就想能否模拟人脑的功能用于解决其他问题,这就发展出人工神经网络。
人工神经网络(artificial neural network,缩写ANN),是一种模仿生物神经网络的结构和功能的数学模型或计算模型。神经网络由大量的人工神经元联结进行计算。大多数情况下人工神经网络能在外界信息的基础上改变内部结构,是一种自适应系统。现代神经网络是一种非线性统计性数据建模工具,常用来对输入和输出间复杂的关系进行建模,或用来探索数据的模式。
神经网络是一种运算模型,由大量的节点(或称“神经元”,或“单元”)和之间相互联接构成。每个节点代表一种特定的输出函数,称为激励函数(activation function)。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重(weight),这相当于人工神经网络的记忆。网络的输出则依网络的连接方式,权重值和激励函数的不同而不同。而网络自身通常都是对自然界某种算法或者函数的逼近,也可能是对一种逻辑策略的表达。

  • samples

  • 识别流程

流程如图,首先要对数据进行处理,这个主要是批量读取图片和特征提取的过程,特征提取的方法很多,这里只挑选最简单的来实现,然后是训练出一个神经网络的模型,最后用测试数据进行测试。为了方便,这里的神经网络的创建,训练和测试采用Matlab函数来实现。

  • 构造标签

要构造出适合神经网络的标签,在这个例子中有10个类,若为某个标签,那么这个位置的值为1,其余为0。

  • Matlab实现代码

数字特征提取部分

featureextract.m

% featureextract 
数字特征提取部分

clear;

clc;

% global定义全局变量P T,by:chen

global P
T;

 

I = imread('0.bmp');

% 读入数字图片,为个人用画图板制作的图片

p(1,:)=inputvar(I);

% inputvar(x)函数为特征提取函数,对第一个0样本的图片进行特征提取

 

%I = imread('00.bmp');

I = imread('cccc0.bmp');

p(2,:)=inputvar(I);

% 读入第二个关于字符0的样本

 

I = imread('000.bmp');

p(3,:)=inputvar(I);

 

I = imread('0000.bmp');

p(4,:)=inputvar(I);

 

I = imread('1.bmp');

p(5,:)=inputvar(I);

 

%I = imread('11.bmp');

I = imread('cc15.bmp');

p(6,:)=inputvar(I);

 

I = imread('111.bmp');

p(7,:)=inputvar(I);

 

I = imread('1111.bmp');

p(8,:)=inputvar(I);

 

I = imread('2.bmp');

p(9,:)=inputvar(I);

 

I = imread('22.bmp');

p(10,:)=inputvar(I);

 

%I = imread('222.bmp');

I = imread('cccc2.bmp');

p(11,:)=inputvar(I);

 

I = imread('2222.bmp');

p(12,:)=inputvar(I);

 

%I = imread('3.bmp');

I = imread('cccc3.bmp');

p(13,:)=inputvar(I);

 

I = imread('33.bmp');

p(14,:)=inputvar(I);

 

I = imread('333.bmp');

p(15,:)=inputvar(I);

 

I = imread('3333.bmp');

p(16,:)=inputvar(I);

 

I = imread('4.bmp');

%I = imread('cc444.bmp');

p(17,:)=inputvar(I);

 

I = imread('44.bmp');

p(18,:)=inputvar(I);

 

I = imread('444.bmp');

p(19,:)=inputvar(I);

 

%I = imread('4444.bmp');

I = imread('cc444.bmp');

p(20,:)=inputvar(I);

 

%I = imread('5.bmp');

I = imread('cccc5.bmp');

p(21,:)=inputvar(I);

 

I = imread('55.bmp');

p(22,:)=inputvar(I);

 

I = imread('555.bmp');

p(23,:)=inputvar(I);

 

I = imread('5555.bmp');

p(24,:)=inputvar(I);

 

I = imread('6.bmp');

p(25,:)=inputvar(I);

 

I = imread('66.bmp');

p(26,:)=inputvar(I);

 

I = imread('666.bmp');

p(27,:)=inputvar(I);

 

I = imread('6666.bmp');

p(28,:)=inputvar(I);

 

I = imread('7.bmp');

p(29,:)=inputvar(I);

 

I = imread('77.bmp');

p(30,:)=inputvar(I);

 

I = imread('777.bmp');

p(31,:)=inputvar(I);

 

I = imread('7777.bmp');

p(32,:)=inputvar(I);

 

I = imread('8.bmp');

p(33,:)=inputvar(I);

 

I = imread('88.bmp');

p(34,:)=inputvar(I);

 

I = imread('888.bmp');

p(35,:)=inputvar(I);

 

I = imread('8888.bmp');

p(36,:)=inputvar(I);

 

I = imread('9.bmp');

p(37,:)=inputvar(I);

 

I = imread('99.bmp');

p(38,:)=inputvar(I);

 

I = imread('999.bmp');

p(39,:)=inputvar(I);

 

I = imread('9999.bmp');

p(40,:)=inputvar(I);

 

I = imread('test0.bmp');

p(41,:)=inputvar(I);

 

I = imread('test00.bmp');

p(42,:)=inputvar(I);

 

I = imread('test1.bmp');

p(43,:)=inputvar(I);

 

I = imread('test11.bmp');

p(44,:)=inputvar(I);

 

I = imread('test2.bmp');

p(45,:)=inputvar(I);

 

I = imread('test22.bmp');

p(46,:)=inputvar(I);

 

I = imread('test3.bmp');

p(47,:)=inputvar(I);

 

I = imread('test33.bmp');

p(48,:)=inputvar(I);

 

I = imread('test4.bmp');

p(49,:)=inputvar(I);

 

I = imread('test44.bmp');

p(50,:)=inputvar(I);

 

I = imread('test5.bmp');

p(51,:)=inputvar(I);

 

I = imread('test55.bmp');

p(52,:)=inputvar(I);

 

I = imread('test6.bmp');

p(53,:)=inputvar(I);

 

I = imread('test7.bmp');

p(54,:)=inputvar(I);

 

I = imread('test8.bmp');

p(55,:)=inputvar(I);

 

I = imread('test9.bmp');

p(56,:)=inputvar(I);

 

P = p;

% 输入的训练与测试样本集

T = [0 0 0 0;

    0 0 0 0;

    0 0 0 0;

    0 0 0 0;

    0 0 0 1;

    0 0 0 1;

    0 0 0 1;

    0 0 0 1;

    0 0 1 0;

    0 0 1 0;

    0 0 1 0;

    0 0 1 0;

    0 0 1 1;

    0 0 1 1;

    0 0 1 1;

    0 0 1 1;

    0 1 0 0;

    0 1 0 0;

    0 1 0 0;

    0 1 0 0;

    0 1 0 1;

    0 1 0 1;

    0 1 0 1;

    0 1 0 1;

    0 1 1 0;

    0 1 1 0;

    0 1 1 0;

    0 1 1 0;

    0 1 1 1;

    0 1 1 1;

    0 1 1 1;

    0 1 1 1;

    1 0 0 0;

    1 0 0 0;

    1 0 0 0;

    1 0 0 0;

    1 0 0 1;

    1 0 0 1;

    1 0 0 1;

    1 0 0 1

    0 0 0 0

    0 0 0 0

    0 0 0 1

    0 0 0 1

    0 0 1 0

    0 0 1 0

    0 0 1 1

    0 0 1 1

    0 1 0 0

    0 1 0 0

    0 1 0 1

    0 1 0 1

    0 1 1 0

    0 1 1 1

    1 0 0 0

    1 0 0 1];

% 输出的训练与测试样本

ttest = [0 0 0 0   

    0 0 0 1   

    0 0 1 0   

    0 0 1 1   

    0 1 0 0   

    0 1 0 1

    0 1 1 0

    0 1 1 1

    1 0 0 0

    1 0 0 1];

% 1至9数字的标准输出

 

P = P';

T = T';

ttest = ttest';

save featureextractPTttest

% 保存特征提取后的输入输出样本数据,生成mat文件以便训练与测试时对样本数据的调用

特征提取

% inputvar  
特征提取

function y=inputvar(I)

% inputvar   特征提取

b = find(I>130);%I:读入的待辨认的数字图片,find(I>130):找出I中大于130的坐标,返回的是线性索引

I(b) = 1;%将图像中大于130的地方置1

 % 对数字图片进行二值化处理,读入的图片形式简单以致于二值化方法简单

% 图像预处理部分

 

[m,n] = size(I);%获取图片的尺寸,m=16,n=8

p = zeros(1,17);%产生一个1*17的零向量

for
k=1:4

    for i=1+(k-1)*4:m/4+(k-1)*4

        for j=1:n/2

            if I(i,j)==0

                p(k) = p(k)+1;

            else

                p(k) = p(k);

            end

        end

        for j=n/2+1:n

            if I(i,j)==0

                p(k+4) = p(k+4)+1;

            else

                p(k+4) = p(k+4);

            end

        end

    end

end

 % 把图片分成八个独立区域计算各自的图象密度,作为部分特征向量

p(9) = p(1)+p(2);

p(10) = p(3)+p(4);

p(11) = p(5)+p(6);

p(12) = p(7)+p(8);

p(13) = p(1)+p(5);

p(14) = p(2)+p(6);

p(15) = p(3)+p(7);

p(16) = p(4)+p(8);

p(17) = p(9)+p(10)+p(11)+p(12);

y = p/128;

 % 合并区域的图像密度作为其他部分特征向量

网络训练与仿真部分

网络训练与仿真部分

% bpnntrain  网络训练与仿真部分

clear

clc

 

%load featureextract;

load('D:\featureextract');

% 调用输入输出样本数据

P_train = P(:,1:40);

%P_train:训练样本集合

T_train = T(:,1:40);

P_test = P(:,40:56);

T_test = T(:,40:56);

 

echo on

net=newff(minmax(P_train),[9 4],{'tansig','tansig','tansig'},'trainlm');

%newff:建立一个BP网络

%minmax(P_train):对神经网络输入的最大最小值的限制

%[9 4]:神经网络的层结构

%{'tansig','tansig','tansig'}:神经网络各层转移函数

%'trainlm':训练函数

% 利用工具箱建立前向BP网络,输入输出隐层的传递函数均为S型的正切函数,使用Levenberg-Marquard算法进行训练

% 隐层设置9个神经元,4个神经元输出

net = init(net);

% 网络初始化

[m1,n1]=size(net.IW{1,1});

net.IW{1,1}=0.3*ones(m1,n1);

% 初始化当前输入层权值

[m2,n2]=size(net.LW{2,1});

net.LW{2,1}=0.3*ones(m2,n2);

% 初始化隐层与输出层的连接权值

net.trainParam.show=100; %显示的间隔次数

net.trainParam.lr=0.01; %网络学习速率

net.trainParam.mc=0.9; %动量因子

net.trainParam.epochs=1000; %最大训练次数

net.trainParam.goal=0.001;%性能目标值

% 设置训练参数

[net,tr] = train(net,P_train,T_train);

% 静态批处理方式进行网络训练,net:更新了权值的神经网络,tr:训练次数和每次训练的误差

fig = plotperf(tr)

 

Y = sim(net,P_train);

% 对训练后的网络进行仿真

E = T_train-Y;

perf=mse(E)

% 计算仿真误差

echo off

 

save bpnntrainnetfig

 

 

 

网络测试与检测部分

% nnceshi   网络测试与检测部分

function result = TestDigit( img )

%UNTITLED Summary of this function goes here

%   Detailed
explanation goes here

 

% global定义全局变量P T,by:chen

global P
T;

% 数字特征提取

%load featureextract;

load('D:\featureextract');

 

% 网络训练与仿真部分

%load bpnntrain net;

load('D:\bpnntrain');

 

% P_test:测试样本的特征向量

P_test = P(:,40:56);

T_test = T(:,40:56);

 

% 对训练后的网络进行测试,net:训练完成了的网络,P_test:测试样本的特征向量,Y:神经网络的输出

% 仿真

Y = sim(net,P_test);

 

E = T_test-Y;

 

% 计算测试误差,暂时注释掉======
by:chenqp

%perf=mse(E)

perf=mse(E);

% 读入待辨认的数字图片,检测网络

I = imread(img);

% 调用特征提取函数提取数据特征

ptest = inputvar(I);

 

ptest = ptest';

Y = sim(net,ptest);

D = round(Y);%对Y取整

Num = 8*D(1,1)+4*D(2,1)+2*D(3,1)+D(4,1);

% 暂时注释掉ttest======= by:chenqp

% ttest = ttest(:,Num+1)

ttest = ttest(:,Num+1);

E = ttest-abs(Y);

%均方误差

perf=mse(E);

result = Num;

 

end

 

封装成C#可以调用的DLL

C#调用代码实现

using System;
using System.Collections.Generic;
using QpSolution;
using MathWorks.MATLAB.NET.Arrays;
using MathWorks.MATLAB.NET.Utility; namespace TestMatlab
{
class Program
{
static void Main(string[] args)
{
// 直接使用Math.Pow计算x的y次方
List<double> x = new List<double>();
List<double> y = new List<double>();
List<double> z1 = new List<double>();
List<double> z2 = new List<double>();
Random random = new Random(); for (int i = 0; i < 1000000; i++)
{
x.Add(random.Next(1000) * random.NextDouble());
y.Add(random.Next(1000) * random.NextDouble());
}
DateTime a = DateTime.Now;
for (int i = 0; i < x.Count; i++)
{
z1.Add(Math.Pow(x[i], y[i]));
}
DateTime b = DateTime.Now;
// 直接使用Math.Pow计算x的y次方,第一次运算花费时间ms
Console.WriteLine((b - a).TotalMilliseconds); a = DateTime.Now;
for (int i = 0; i < x.Count; i++)
{
z2.Add(Math.Pow(x[i], y[i]));
}
b = DateTime.Now;
// 直接使用Math.Pow计算x的y次方,第二次运算花费时间ms
Console.WriteLine((b - a).TotalMilliseconds); a = DateTime.Now;
TestClass tc1 = new TestClass();
var z3 = tc1.TestFun((MWNumericArray)x.ToArray(), (MWNumericArray)y.ToArray()).ToArray();
b = DateTime.Now;
Console.WriteLine((b - a).TotalMilliseconds); a = DateTime.Now;
TestClass tc2 = new TestClass();
var z4 = tc2.TestFun((MWNumericArray)x.ToArray(), (MWNumericArray)y.ToArray()).ToArray();
b = DateTime.Now;
Console.WriteLine((b - a).TotalMilliseconds); // MWArray是数据类型的一个父类,下面包括了很多数据类
MWNumericArray mw1 = new MWNumericArray(MWArrayComplexity.Real, 1);
mw1[1] = 2;
MWNumericArray mw2 = new MWNumericArray(MWArrayComplexity.Real, 1);
mw2[1] = 3;
var z5 = tc1.TestFun(mw1, mw2);
Console.WriteLine(z5); // 8 // 传入字符串
MWCharArray str = "D:\\test7.bmp";
var z6 = tc1.TestChar(str);
Console.WriteLine(z6); // 测试传入的文件是否存在,并拿到Matlab返回值
MWCharArray file = "D:\\test7.bmp";
var z7 = tc1.TestFileExist(file);
Console.WriteLine(z7); // 测试人工神经网络识别手写数字,返回matlab函数识别结果
MWCharArray img1 = "D:\\testPic\\c2.bmp";
Console.WriteLine("开始识别第1个图片....");
var pic1 = tc1.TestDigit(img1);
Console.WriteLine("第1个图片识别结果为:" + pic1); MWCharArray img2 = "D:\\testPic\\cccc0.bmp";
Console.WriteLine("开始识别第2个图片....");
var pic2 = tc1.TestDigit(img2);
Console.WriteLine("第2个图片识别结果为:" + pic2); MWCharArray img3 = "D:\\testPic\\cccc2.bmp";
Console.WriteLine("开始识别第3个图片....");
var pic3 = tc1.TestDigit(img3);
Console.WriteLine("第3个图片识别结果为:" + pic3); MWCharArray img4 = "D:\\testPic\\cccc3.bmp";
Console.WriteLine("开始识别第4个图片....");
var pic4 = tc1.TestDigit(img4);
Console.WriteLine("第4个图片识别结果为:" + pic4); MWCharArray img5 = "D:\\testPic\\cccc5.bmp";
Console.WriteLine("开始识别第5个图片....");
var pic5 = tc1.TestDigit(img5);
Console.WriteLine("第5个图片识别结果为:" + pic5); MWCharArray img6 = "D:\\testPic\\abc7.bmp";
Console.WriteLine("开始识别第6个图片....");
var pic6 = tc1.TestDigit(img6);
Console.WriteLine("第6个图片识别结果为:" + pic6); MWCharArray img7 = "D:\\testPic\\abc8.bmp";
Console.WriteLine("开始识别第7个图片....");
var pic7 = tc1.TestDigit(img7);
Console.WriteLine("第7个图片识别结果为:" + pic7); Console.Read(); }
}
}

  

运行结果

最新文章

  1. Nodejs:Path对象
  2. 移动端的拖拽这个demo实现的功能
  3. MySql密码忘记解决方法
  4. ACM/ICPC 之 Floyd练习六道(ZOJ2027-POJ2253-POJ2472-POJ1125-POJ1603-POJ2607)
  5. [译]MongoDb生产环境注意事项
  6. Chomp!游戏 (组合游戏Combinatorial Games)
  7. IPicture总结
  8. D3.js:完整的柱形图
  9. Ztree当节点没有下级时不显示下拉图标
  10. [补档][NOIP2015] 斗地主
  11. 在nagios中监控windows主机系统地址的状态
  12. Perl线程队列:Thread::Queue
  13. licecap软件——简单做出app的效果gif图
  14. spring-boot (四) springboot+mybatis多数据源最简解决方案
  15. Android Studio 学习(三) 广播
  16. LeetCode: First Missing Positive 解题报告
  17. linux系统修改系统时间与时区
  18. spring boot实现ssm(1)功能
  19. redis系列--redis4.0深入持久化
  20. 「Vue」过滤器

热门文章

  1. linux多核cpu下的负载查看
  2. centos 6.7下 elasticsearch的安装
  3. 【五子棋AI循序渐进】——多线程搜索
  4. Android自动化测试工具——monkey简介及入门
  5. am335x 更改调试串口
  6. linux下安装编译php的curl扩展
  7. throttle在程序中的作用
  8. jq 页面延时刷新
  9. zjuoj 3605 Find the Marble
  10. 9.请写出PHP5权限控制修饰符