- 手寫數字識別實現
設計技術參數:通過由數字構成的圖像,自動實現幾個不同數字的識別,設計識別方法,有較高的識別率
關鍵字:二值化 投影 矩陣 目標定位 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(); } } }
運行結果