摘要
本程序主要參照論文,《基於OpenCV的脫機手寫字符識別技術》實現了,對於手寫阿拉伯數字的識別工作。識別工作分為三大步驟:預處理,特征提取,分類識別。預處理過程主要找到圖像的ROI部分子圖像並進行大小的歸一化處理,特征提取將圖像轉化為特征向量,分類識別采用k-近鄰分類方法進行分類處理,最后根據分類結果完成識別工作。
程序采用Microsoft Visual Studio 2010與OpenCV2.4.4在Windows 7-64位旗艦版系統下開發完成。並在Windows xp-32位系統下測試可用。
主流程圖:
細化流程圖:
預處理的過程就是找到圖像的ROI區域的過程,如下圖所示:
首先找到數字的邊界框,然后大小歸一化數字圖片,主要流程如下圖所示:
主要代碼:
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個數字
{
for( j = 0; j<train_samples;j++)//每個數字50個樣本
{
//加載所有的樣本pbm格式圖像作為訓練
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);
//生成訓練矩陣,每個圖像作為一個向量
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 );
//轉換換 8 bits image to 32位浮點數圖片取值區間為[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. 分類識別
識別方法采用knn近鄰分類法。這個算法首先貯藏所有的訓練樣本,然后通過分析(包括選舉,計算加權和等方式)一個新樣本周圍K個最近鄰以給出該樣本的相應值。這種方法有時候被稱作“基於樣本的學習”,即為了預測,我們對於給定的輸入搜索最近的已知其相應的特征向量。
K最近鄰(k-Nearest Neighbor,KNN)分類算法,是一個理論上比較成熟的方法,也是最簡單的機器學習算法之一。該方法的思路是:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。 KNN方法雖然從原理上也依賴於極限定理,但在類別決策時,只與極少量的相鄰樣本有關。由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合。
識別工作主要有以下幾個步驟:
1. 初始化機器學習算法,及其訓練
knn=new CvKNearest( trainData, trainClasses, 0, false, K );
因為trainData, trainClasses數據已得到。訓練在CvKNearest算法初始化中已經完成
2. 識別
獲取識別測試的數據,testData
result=knn->find_nearest(testData,K,0,0,nearest,0);
result為返回的識別的結果
4. 實驗結果
在knn參數k=5,子圖像向量大小選取128*128像素,訓練樣本50副圖片,測試樣本50副圖片,系統誤識率為7.4%。對於用戶手寫阿拉伯數字2的識別結果為2,識別比較准確。
5. 未來的工作
本程序主要參照網上的一些實例完成了部署跟實驗工作,雖然僅僅完成了手寫阿拉伯數字的識別工作,但是字符識別的一些原理工作都是相同的,未來能夠從一下幾個方面進行提高:
1. 提高程序的識別准確率,從一些文獻實現的結果來看,簡單的模型結合大量的訓練樣本,往往效果比復雜的模型結合少量訓練樣本實現的效果好。
2. 擴展程序的功能,從實現簡單的字符到最終實現識別手寫漢字等。
3. 提高識別速度,改進算法為並行算法,實現如聯機在線識別等。
6.主要參考文獻:
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.項目打包下載
http://download.csdn.net/detail/wangyaninglm/6631953
8.手寫字符識別的復雜版本,這個增加了一些OpenGL技術,程序比較復雜