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#调用代码实现
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();
}
}
}