C#中调用Matlab人工神经网络算法实现手写数字识别

  • 手写数字识别实现

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

关键字:二值化  投影  矩阵  目标定位  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#调用代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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();
 
         }
     }
}

  

运行结果

 C#中调用Matlab人工神经网络算法实现手写数字识别_第1张图片

你可能感兴趣的:(C#中调用Matlab人工神经网络算法实现手写数字识别)