libsvm Minist Hog 手寫體識別(源碼文件)


以上是我上一篇文章中的代碼實現,里面分別用了opencv中的SVM和LibSVM,opencv的SVM用起來更方便,但貌似內部其實也是基於Libsvm,同樣的參數訓練出來的結果是一致的,里面有Libsvm的調用過程,如果用libsvm需要在工程里面添加libsvm的源碼文件分別是svm.h和svm.cpp,林智仁的庫里自帶的那兩個核心文件即可。
libsvm的用法讓人更感覺是在用C的寫法,opencv封裝過的易用性更好,稍后我會把工程文件放到github上供大家下載,若有什么錯誤,還請批評指教~,這里用的是Minist的數據集,圖像時我經過處理后的單張圖像,大小為20*20,里面有詳細的函數使用說明

[https://github.com/YihangLou/SVM-Minist-HandWriting-Recognition] Github上的工程鏈接

// DigitsRec_HOG_SVM.cpp : 定義控制台應用程序的入口點。
#include "opencv2/opencv.hpp"
#include "fstream"
#include "svm.h"
using namespace std;
using namespace cv;

#define srcfeature

vector<string> trainImageList;//訓練圖像列表,此處路徑
vector<int> trainLabelList;   //標簽
vector<string> testImageList;//訓練圖像列表,此處路徑
string trainImageFile= "D:\\WorkSpace\\homework\\PatternRecognization\\第一次作業\\minist\\train_image\\imagelist.txt";
string testImageFile = "D:\\WorkSpace\\homework\\PatternRecognization\\第一次作業\\minist\\test_image\\imagelist.txt";
string testBasePath = "D:\\WorkSpace\\homework\\PatternRecognization\\第一次作業\\minist\\test_image\\";
string trainBasePath = "D:\\WorkSpace\\homework\\PatternRecognization\\第一次作業\\minist\\train_image\\";
string SVMModel ="svm_model.xml";
CvMat * dataMat;
CvMat * labelMat;

//***************************************************************
// 名稱:    readTrainFileList
// 功能:    讀取訓練的圖像列表和圖像的位置
// 權限:    public 
// 返回值:  void
// 參數:    string trainImageFile 文件列表
// 參數:    string basePath 基地址
// 參數:    vector<string> & trainImageList 圖像路徑list
// 參數:    vector<int> & trainLabelList 圖像標簽list
//***************************************************************
void readTrainFileList(string trainImageFile, string basePath, vector<string> &trainImageList,  vector<int> &trainLabelList)
{
	ifstream readData( trainImageFile );
	string buffer;
	while( readData )
	{    
		if( getline( readData, buffer))    
		{    
			int label = int((buffer[0])-'0');//在我這里路徑中第一個文件夾就是類別
			trainLabelList.push_back( label);  
			trainImageList.push_back( buffer );//圖像路徑       
		}    
	}    
	readData.close();
	cout<<"Read Train Data Complete"<<endl;
}

//***************************************************************
// 名稱:    readTestFileList
// 功能:    讀測試文件
// 權限:    public 
// 返回值:  void
// 參數:    string testImageFile
// 參數:    string basePath
// 參數:    vector<string> & testImageList 測試圖像列表
//***************************************************************
void readTestFileList(string testImageFile, string basePath, vector<string> &testImageList)
{
	ifstream readData( testImageFile );  //加載測試圖片集合
	string buffer;
	while( readData )
	{    
		if( getline( readData, buffer))    
		{    
			testImageList.push_back( buffer );//圖像路徑       
		}    
	}    
	readData.close();
	cout<<"Read Test Data Complete"<<endl;
}

//***************************************************************
// 名稱:    processHogFeature
// 功能:    計算Hog特征
// 權限:    public 
// 返回值:  void
// 參數:    vector<string> trainImageList
// 參數:    vector<int> trainLabelList
// 參數:    CvMat *  & dataMat
// 參數:    CvMat *  & labelMat
//***************************************************************
void processHogFeature(vector<string> trainImageList,vector<int> trainLabelList, CvMat * &dataMat,CvMat * &labelMat)
{
	
	 int trainSampleNum = trainImageList.size();
	 dataMat = cvCreateMat( trainSampleNum, 324, CV_32FC1 );  //324為Hog feature Size
	 cvSetZero( dataMat );     
	 labelMat = cvCreateMat( trainSampleNum, 1, CV_32FC1 );    
	 cvSetZero( labelMat );    
	 IplImage* src;   
	 IplImage* trainImg=cvCreateImage(cvSize(20,20),8,3);//20 20

	for( int i = 0; i != trainImageList.size(); i++ ) 
	{    
		src=cvLoadImage( (trainBasePath  + trainImageList[i]).c_str(),1);    
		if( src == NULL )    
		{    
			cout<<" can not load the image: "<<(trainBasePath  + trainImageList[i]).c_str()<<endl;    
			continue;    
		}    
		//cout<<"Calculate Hog Feature "<<(trainBasePath  + trainImageList[i]).c_str()<<endl;    

		cvResize(src,trainImg);     
		HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);      
		vector<float>descriptors;    
		hog->compute(trainImg, descriptors,Size(1,1), Size(0,0));     

		int j =0; 
		for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)    
		{    
			cvmSet(dataMat,i,j,*iter);//存儲HOG特征 
			j++;    
		}       
		cvmSet( labelMat, i, 0, trainLabelList[i] );    
		//cout<<"Image and label "<<trainImageList[i].c_str()<<" "<<trainLabelList[i]<<endl;    
	}    
	cout<<"Calculate Hog Feature Complete"<<endl;
	cout<<dataMat<<endl;
}

void processNonFeature(vector<string> trainImageList,vector<int> trainLabelList, CvMat * &dataMat,CvMat * &labelMat)
{

	int trainSampleNum = trainImageList.size();
	dataMat = cvCreateMat( trainSampleNum, 400, CV_32FC1 );  //324為Hog feature 大小,需提前設置 
	cvSetZero( dataMat );     
	labelMat = cvCreateMat( trainSampleNum, 1, CV_32FC1 );    
	cvSetZero( labelMat );    
	IplImage* src;   
	IplImage* resizeImg=cvCreateImage(cvSize(20,20),8,3);//20 20是訓練樣本的大小

	for( int i = 0; i != trainImageList.size(); i++ ) 
	{    
		src=cvLoadImage( (trainBasePath  + trainImageList[i]).c_str(),1);    
		if( src == NULL )    
		{    
			cout<<" can not load the image: "<<(trainBasePath  + trainImageList[i]).c_str()<<endl;    
			continue;    
		}    
		//cout<<"Calculate Hog Feature "<<(trainBasePath  + trainImageList[i]).c_str()<<endl;    

		cvResize(src,resizeImg);     
		IplImage * grayImage = cvCreateImage(cvGetSize(resizeImg), IPL_DEPTH_8U, 1);
		cvCvtColor(resizeImg,grayImage,CV_BGR2GRAY);
		//二值化圖像
		IplImage * binaryImage = cvCreateImage(cvGetSize(grayImage),IPL_DEPTH_8U,1);
		cvThreshold(grayImage,binaryImage,25,255,CV_THRESH_BINARY);
		//cvNamedWindow("src");
		//cvShowImage("src", src);

		//cvNamedWindow("show");
		//cvShowImage("show", binaryImage);
		//cvWaitKey(0);//這里是看一下二值化的效果怎么樣
		HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);      
		vector<float>descriptors;    


		int j =0; //j為矩陣的水平坐標,要把特征從vector中拷貝過來
		uchar * tmp = new uchar;
		for(int n=0;n<binaryImage->height;n++)  
		{	for(int m=0;m<binaryImage->width;m++)  
		{	
			*tmp=((uchar *)(binaryImage->imageData + n*binaryImage->widthStep))[m];  
			cvmSet(dataMat,i,j,*tmp);//存儲HOG特征 
			j++;
		}
		}  

		cvmSet( labelMat, i, 0, trainLabelList[i] );    
		//cout<<"Image and label "<<trainImageList[i].c_str()<<" "<<trainLabelList[i]<<endl;    
	}    
	cout<<"Calculate Hog Feature Complete"<<endl;

}

//***************************************************************
// 名稱:    trainSVM
// 功能:    此處用的是opencv的SVM訓練
// 權限:    public 
// 返回值:  void
// 參數:    CvMat *  & dataMat
// 參數:    CvMat *  & labelMat
//***************************************************************
void trainSVM(CvMat * & dataMat,CvMat * & labelMat )
{
	cout<<"train svm start"<<endl;
	cout<<dataMat<<endl;
	CvSVM svm;
	CvSVMParams param;//這里是SVM訓練相關參數  
	CvTermCriteria criteria;      
	criteria = cvTermCriteria( CV_TERMCRIT_EPS, 1000, FLT_EPSILON );      
	param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria );          

	svm.train( dataMat, labelMat, NULL, NULL, param );//訓練數據          
	svm.save( SVMModel.c_str());  
	cout<<"SVM Training Complete"<<endl;
}

//***************************************************************
// 名稱:    trainLibSVM
// 功能:    此處用的是LibSVM庫的SVM訓練
// 權限:    public 
// 返回值:  void
// 參數:    CvMat * & dataMat
// 參數:    CvMat *  & labelMat
//***************************************************************
void trainLibSVM(CvMat *& dataMat, CvMat * & labelMat)
{
	cout<<"LibSVM start"<<endl;
	//配置SVM參數
	svm_parameter param;
	//param.svm_type = C_SVC;
	param.svm_type = EPSILON_SVR;
	param.kernel_type = RBF;
	param.degree = 10.0;
	param.gamma = 0.09;
	param.coef0 = 1.0;
	param.nu = 0.5;
	param.cache_size = 1000;
	param.C = 10.0;
	param.eps = 1e-3;
	param.p = 1.0;

	//svm_prob讀取
	svm_problem svm_prob;
	
	int sampleNum = dataMat->rows;
	int vectorLength = dataMat->cols;

	svm_prob.l = sampleNum;
	svm_prob.y = new double [sampleNum];

	for (int i = 0; i < sampleNum; i++)
	{
		svm_prob.y[i] = cvmGet(labelMat,i,0);
	}

	cout<<"LibSVM middle"<<endl;
	svm_prob.x = new  svm_node * [sampleNum];

	for (int i = 0; i < sampleNum; i++)
	{
		svm_node * x_space = new svm_node [vectorLength + 1];
		for (int j = 0; j < vectorLength; j++)
		{
			x_space[j].index = j;
			x_space[j].value = cvmGet(dataMat,i,j);
			
		}
		x_space[vectorLength].index = -1;//注意,結束符號,一開始忘記加了

		svm_prob.x[i] = x_space;
	}

	cout<<"LibSVM end"<<endl;
	svm_model * svm_model = svm_train(&svm_prob, &param);
#ifdef srcfeature
	svm_save_model("libsvm_minist_src_feature_model_.model",svm_model);
#else
	svm_save_model("libsvm_minist_model.model",svm_model);
#endif
	for (int i=0 ; i < sampleNum; i++)
	{
		delete [] svm_prob.x[i];
	}

	delete [] svm_prob.y;
	svm_free_model_content(svm_model);
}

//***************************************************************
// 名稱:    testSVM
// 功能:    測試opencv訓練的SVM准確率
// 權限:    public 
// 返回值:  void
// 參數:    vector<string> testImageList
// 參數:    string SVMModel
//***************************************************************
void testSVM(vector<string> testImageList, string SVMModel)
{
	CvSVM svm;
	svm.load(SVMModel.c_str());//加載模型文件

	IplImage* testImage;  
	IplImage* tempImage;
	char buffer[512]; 

	ofstream ResultOutput( "predict_result.txt" );//把預測結果存儲在這個文本中   
	for( int j = 0; j != testImageList.size(); j++ )//依次遍歷所有的待檢測圖片    
	{    
		testImage = cvLoadImage( (testBasePath+testImageList[j]).c_str(), 1);    
		if( testImage == NULL )    
		{    
			cout<<" can not load the image: "<<(testBasePath+testImageList[j]).c_str()<<endl;    
			continue;    
		}
		tempImage =cvCreateImage(cvSize(20,20),8,3);
		cvZero(tempImage);    
		cvResize(testImage,tempImage);    
		HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);       
		vector<float>descriptors; 

		hog->compute(tempImage, descriptors,Size(1,1), Size(0,0));       
		CvMat* TempMat=cvCreateMat(1,descriptors.size(),CV_32FC1);    
		int n=0;    
		for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)    
		{    
			cvmSet(TempMat,0,n,*iter);    
			n++;    
		}       

		int resultLabel = svm.predict(TempMat);//檢測結果
		sprintf( buffer, "%s  %d\r\n",testImageList[j].c_str(),resultLabel );
		ResultOutput<<buffer;  
	}
	cvReleaseImage(&testImage);
	cvReleaseImage(&tempImage);
	ResultOutput.close();   
	cout<<"SVM Predict Complete"<<endl;
}

//***************************************************************
// 名稱:    testLibSVM
// 功能:    測試LisbSVM訓練的模型的分類性能
// 權限:    public 
// 返回值:  void
// 參數:    string LibSVMModelFile
// 參數:    vector<string> testImageList
// 參數:    string SVMModel
//***************************************************************
void testLibSVM(string LibSVMModelFile, vector<string> testImageList, string SVMModel)
{

	svm_model * svm = svm_load_model(LibSVMModelFile.c_str());

	IplImage* testImage;  
	IplImage* tempImage;
	char buffer[512]; 

	ofstream ResultOutput( "libsvm_predict_result.txt" ); 
	for( int j = 0; j != testImageList.size(); j++ )//依次遍歷所有的待檢測圖片    
	{    
		testImage = cvLoadImage( (testBasePath+testImageList[j]).c_str(), 1);    
		if( testImage == NULL )    
		{    
			cout<<" can not load the image: "<<(testBasePath+testImageList[j]).c_str()<<endl;    
			continue;    
		}
		tempImage =cvCreateImage(cvSize(20,20),8,3);
		cvZero(tempImage);    
		cvResize(testImage,tempImage);    
		HOGDescriptor *hog=new HOGDescriptor(cvSize(20,20),cvSize(10,10),cvSize(5,5),cvSize(5,5),9);       
		vector<float>descriptors; 

		hog->compute(tempImage, descriptors,Size(1,1), Size(0,0));  

		svm_node * inputVector = new svm_node [ descriptors.size()+1];
		int n = 0;
		for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)    
		{     
			inputVector[n].index = n;
			inputVector[n].value = *iter;
			n++;
		}       
		inputVector[n].index = -1;
		
		int resultLabel = svm_predict(svm,inputVector);//分類結果
		sprintf( buffer, "%s  %d\r\n",testImageList[j].c_str(),resultLabel );
		ResultOutput<<buffer;  
		delete [] inputVector;
	}
	svm_free_model_content(svm);
	cvReleaseImage(&testImage);
	cvReleaseImage(&tempImage);
	ResultOutput.close();   
	cout<<"SVM Predict Complete"<<endl;
}

//***************************************************************
// 名稱:    releaseAll
// 功能:    釋放相應的資源
// 權限:    public 
// 返回值:  void
//***************************************************************
void releaseAll()
{

	cvReleaseMat( &dataMat ); 
	cvReleaseMat( &labelMat);
	cout<<"Release All Complete"<<endl;
}

//***************************************************************
// 名稱:    main
// 功能:    這里用了兩種SVM,一種是opencv中的,一種是libsvm中的,訓練測試需要選擇相對應的svm
// 權限:    public 
// 返回值:  int
//***************************************************************
int main()
{

	readTrainFileList(trainImageFile,trainBasePath,trainImageList,trainLabelList);      
	processHogFeature(trainImageList,trainLabelList, dataMat,labelMat);
	//trainSVM(dataMat,labelMat );
	//processNonFeature(trainImageList,trainLabelList, dataMat,labelMat);
	trainLibSVM(dataMat,labelMat);
	//readTestFileList( testImageFile,  testBasePath, testImageList);
	testLibSVM("libsvm_minist_model.model",testImageList,SVMModel);
	//testSVM( testImageList, SVMModel);
	releaseAll();
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM