手寫數字識別實現
設計技術參數:通過由數字構成的圖像,自動實現幾個不同數字的識別,設計識別方法,有較高的識別率
關鍵字:二值化 投影 矩陣 目標定位 Matlab
手寫數字圖像識別簡介:
手寫阿拉伯數字識別是圖像內容識別中較為簡單的一個應用領域,原因有被識別的模式數較少(只有0到9,10個阿拉伯數字)、阿拉伯數字筆畫少並且簡單等。手寫阿拉伯數字的識別采用的方法相對於人臉識別、漢字識別等應用領域來說可以采用更為靈活的方法,例如基於規則的方法、基於有限狀態自動機的方法、基於統計的方法和基於神經網絡的方法等。本文的開始部分先對手寫阿拉伯數字識別的整個處理流程進行論述,而這個流程也可以用於圖像中其他模式的識別。當然這個處理流程也不是唯一的,可以根據不同的模式識別應用場景進行與之不同的預處理流程。
手寫數字圖像識別的主要流程:
第一步:對源圖像進行黑白二值化處理;0數字的二值化(左)和1的二值化處理(右)
第二步:將圖像在水平方向上和豎直方向上進行投影,這樣通過投影圖形就可以區分1和0的特征;
第三步:用投影計算出區域的橫縱坐標,將其分為九份。定位出數字所在圖像中的位置,提取該部分進行分析。
第四步:數字0和1的特征比較與識別
在0和一的比較中發現,在分成的九個區域的中間區域,0中間區域灰度為0,1中間區域灰度為1。
人類之所以能夠思考,學習,判斷,大部分都要歸功於人腦中復雜的神經網絡。雖然現在人腦的機理還沒有完全破譯,但是人腦中神經元之間的連接,信息的傳遞都已為人所知曉。於是人們就想能否模擬人腦的功能用於解決其他問題,這就發展出人工神經網絡。
人工神經網絡(artificial neural network,縮寫ANN),是一種模仿生物神經網絡的結構和功能的數學模型或計算模型。神經網絡由大量的人工神經元聯結進行計算。大多數情況下人工神經網絡能在外界信息的基礎上改變內部結構,是一種自適應系統。現代神經網絡是一種非線性統計性數據建模工具,常用來對輸入和輸出間復雜的關系進行建模,或用來探索數據的模式。
神經網絡是一種運算模型,由大量的節點(或稱“神經元”,或“單元”)和之間相互聯接構成。每個節點代表一種特定的輸出函數,稱為激勵函數(activation function)。每兩個節點間的連接都代表一個對於通過該連接信號的加權值,稱之為權重(weight),這相當於人工神經網絡的記憶。網絡的輸出則依網絡的連接方式,權重值和激勵函數的不同而不同。而網絡自身通常都是對自然界某種算法或者函數的逼近,也可能是對一種邏輯策略的表達。
流程如圖,首先要對數據進行處理,這個主要是批量讀取圖片和特征提取的過程,特征提取的方法很多,這裡只挑選最簡單的來實現,然後是訓練出一個神經網絡的模型,最後用測試數據進行測試。為了方便,這裡的神經網絡的創建,訓練和測試采用Matlab函數來實現。
要構造出適合神經網絡的標簽,在這個例子中有10個類,若為某個標簽,那麼這個位置的值為1,其余為0。
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
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();
}
}
}