基于opencv的手写数字字符识别
?
摘要
本程序主要參照論文,《基于OpenCV的脫機(jī)手寫字符識(shí)別技術(shù)》實(shí)現(xiàn)了,對(duì)于手寫阿拉伯?dāng)?shù)字的識(shí)別工作。識(shí)別工作分為三大步驟:預(yù)處理,特征提取,分類識(shí)別。預(yù)處理過程主要找到圖像的ROI部分子圖像并進(jìn)行大小的歸一化處理,特征提取將圖像轉(zhuǎn)化為特征向量,分類識(shí)別采用k-近鄰分類方法進(jìn)行分類處理,最后根據(jù)分類結(jié)果完成識(shí)別工作。
程序采用Microsoft Visual Studio 2010與OpenCV2.4.4在Windows 7-64位旗艦版系統(tǒng)下開發(fā)完成。并在Windows xp-32位系統(tǒng)下測(cè)試可用。
主流程圖:
?
細(xì)化流程圖:
?
?
?
1.?? 預(yù)處理
預(yù)處理的過程就是找到圖像的ROI區(qū)域的過程,如下圖所示:
?
首先找到數(shù)字的邊界框,然后大小歸一化數(shù)字圖片,主要流程如下圖所示:
?
?
?
主要代碼:
IplImagepreprocessing(IplImage*imgSrc,intnew_width,intnew_height)
{
?????? IplImage* result;
?????? IplImage* scaledResult;
?
?????? CvMat data;
?????? CvMat dataA;
??????CvRect bb;//bounding box
??????CvRect bba;//boundinb box maintain aspect ratio
??????
??????//Find bounding box找到邊界框
?????? bb=findBB(imgSrc);
?????? cvGetSubRect(imgSrc, &data,cvRect(bb.x,bb.y,bb.width,bb.height));
?????? int size=(bb.width>bb.height)?bb.width:bb.height;
?????? result=cvCreateImage( cvSize( size, size ), 8, 1 );
?????? cvSet(result,CV_RGB(255,255,255),NULL);
??????//將圖像放中間,大小歸一化
?????? int x=(int)floor((float)(size-bb.width)/2.0f);
?????? int y=(int)floor((float)(size-bb.height)/2.0f);
?????? cvGetSubRect(result, &dataA,cvRect(x,y,bb.width,bb.height));
?????? cvCopy(&data, &dataA,NULL);
??????//Scale result
?????? scaledResult=cvCreateImage( cvSize( new_width, new_height ), 8, 1 );
?????? cvResize(result, scaledResult, CV_INTER_NN);
??????
??????//Return processed data
??????return *scaledResult;//直接返回處理后的圖片
??????
}
?
?
2.?? 特征提取
在拿到ROI圖像減少了信息量之后,就可以直接用圖片作為向量矩陣作為輸入:
voidbasicOCR::getData()
{
?????? IplImage* src_image;
?????? IplImage prs_image;
?????? CvMat row,data;
?????? char file[255];
?????? int i,j;
?????? for(i =0; i<classes;i++)//總共10個(gè)數(shù)字
?????? {
?????????????for( j = 0; j<train_samples;j++)//每個(gè)數(shù)字50個(gè)樣本
????????????? {
????????????????????
????????????????????//加載所有的樣本pbm格式圖像作為訓(xùn)練
????????????????????if(j<10)
???????????????????????????sprintf(file,"%s%d/%d0%d.pbm",file_path,i,i , j);
????????????????????else
???????????????????????????sprintf(file,"%s%d/%d%d.pbm",file_path,i,i , j);
????????????????????src_image = cvLoadImage(file,0);
????????????????????if(!src_image)
???????????????????? {
???????????????????????????printf("Error: Cant load image %s\n",file);
???????????????????????????//exit(-1);
???????????????????? }
????????????????????//process file
????????????????????prs_image = preprocessing(src_image,size,size);
????????????????????//生成訓(xùn)練矩陣,每個(gè)圖像作為一個(gè)向量
????????????????????cvGetRow(trainClasses, &row,i*train_samples +j);
????????????????????cvSet(&row, cvRealScalar(i));
????????????????????//Set data
????????????????????cvGetRow(trainData, &row,i*train_samples +j);
?
????????????????????IplImage* img = cvCreateImage( cvSize( size, size ),
IPL_DEPTH_32F, 1 );
????????????????????//轉(zhuǎn)換換 8 bits image to 32位浮點(diǎn)數(shù)圖片取值區(qū)間為[0,1]
????????????????????//scale?=?0.0039215?=?1/255;?
????????????????????cvConvertScale(&prs_image,img, 0.0039215, 0);
?
????????????????????cvGetSubRect(img, &data,cvRect(0,0,size,size));
????????????????????
????????????????????CvMat row_header, *row1;
????????????????????//convert data matrix sizexsize to vecor
????????????????????row1 = cvReshape( &data, &row_header, 0, 1 );
????????????????????cvCopy(row1, &row,NULL);
????????????? }
?????? }
}
?
?
3.?? 分類識(shí)別
識(shí)別方法采用knn近鄰分類法。這個(gè)算法首先貯藏所有的訓(xùn)練樣本,然后通過分析(包括選舉,計(jì)算加權(quán)和等方式)一個(gè)新樣本周圍K個(gè)最近鄰以給出該樣本的相應(yīng)值。這種方法有時(shí)候被稱作“基于樣本的學(xué)習(xí)”,即為了預(yù)測(cè),我們對(duì)于給定的輸入搜索最近的已知其相應(yīng)的特征向量。
K最近鄰(k-Nearest Neighbor,KNN)分類算法,是一個(gè)理論上比較成熟的方法,也是最簡(jiǎn)單的機(jī)器學(xué)習(xí)算法之一。該方法的思路是:如果一個(gè)樣本在特征空間中的k個(gè)最相似(即特征空間中最鄰近)的樣本中的大多數(shù)屬于某一個(gè)類別,則該樣本也屬于這個(gè)類別。KNN算法中,所選擇的鄰居都是已經(jīng)正確分類的對(duì)象。該方法在定類決策上只依據(jù)最鄰近的一個(gè)或者幾個(gè)樣本的類別來決定待分樣本所屬的類別。 KNN方法雖然從原理上也依賴于極限定理,但在類別決策時(shí),只與極少量的相鄰樣本有關(guān)。由于KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對(duì)于類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合。
識(shí)別工作主要有以下幾個(gè)步驟:
1. 初始化機(jī)器學(xué)習(xí)算法,及其訓(xùn)練
knn=new CvKNearest( trainData, trainClasses, 0, false, K );
因?yàn)閠rainData, trainClasses數(shù)據(jù)已得到。訓(xùn)練在CvKNearest算法初始化中已經(jīng)完成
2. 識(shí)別
獲取識(shí)別測(cè)試的數(shù)據(jù),testData
result=knn->find_nearest(testData,K,0,0,nearest,0);
result為返回的識(shí)別的結(jié)果
?
?
4.?? 實(shí)驗(yàn)結(jié)果
在knn參數(shù)k=5,子圖像向量大小選取128*128像素,訓(xùn)練樣本50副圖片,測(cè)試樣本50副圖片,系統(tǒng)誤識(shí)率為7.4%。對(duì)于用戶手寫阿拉伯?dāng)?shù)字2的識(shí)別結(jié)果為2,識(shí)別比較準(zhǔn)確。
?
?
?
5.?? 未來的工作
本程序主要參照網(wǎng)上的一些實(shí)例完成了部署跟實(shí)驗(yàn)工作,雖然僅僅完成了手寫阿拉伯?dāng)?shù)字的識(shí)別工作,但是字符識(shí)別的一些原理工作都是相同的,未來能夠從一下幾個(gè)方面進(jìn)行提高:
1.????? 提高程序的識(shí)別準(zhǔn)確率,從一些文獻(xiàn)實(shí)現(xiàn)的結(jié)果來看,簡(jiǎn)單的模型結(jié)合大量的訓(xùn)練樣本,往往效果比復(fù)雜的模型結(jié)合少量訓(xùn)練樣本實(shí)現(xiàn)的效果好。
2.????? 擴(kuò)展程序的功能,從實(shí)現(xiàn)簡(jiǎn)單的字符到最終實(shí)現(xiàn)識(shí)別手寫漢字等。
3.????? 提高識(shí)別速度,改進(jìn)算法為并行算法,實(shí)現(xiàn)如聯(lián)機(jī)在線識(shí)別等。
?
?
6.主要參考文獻(xiàn):
http://blog.csdn.net/jackmacro/article/details/7026211
http://blog.damiles.com/2008/11/basic-ocr-in-opencv/
http://blog.csdn.net/zhubenfulovepoem/article/details/6803150
http://blog.csdn.net/firehood_/article/details/8433077
http://blog.csdn.net/viewcode/article/details/7943341
?
?
7.項(xiàng)目打包下載
http://download.csdn.net/detail/wangyaninglm/6631953
?
8.手寫字符識(shí)別的復(fù)雜版本,這個(gè)增加了一些OpenGL技術(shù),程序比較復(fù)雜
http://blog.csdn.net/wangyaninglm/article/details/41848019
轉(zhuǎn)載于:https://www.cnblogs.com/wangyaning/p/4237032.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的基于opencv的手写数字字符识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL SERVER镜像切换
- 下一篇: perl