OpenCV中的HOG+SVM物體分類
這裡總結網上自己找到的資料,搞一個簡單的框架供大家參考一下。
[cpp] view plaincopyprint?- [cpp] view plaincopyprint
- #include "cv.h"
- #include "highgui.h"
- #include "stdafx.h"
- #include <ml.h>
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <vector>
- usingnamespace
- usingnamespace std;
- int main(int argc, char** argv)
- {
- vector<string> img_path;//輸入檔名變數
- vector<int> img_catg;
- int nLine = 0;
- string buf;
- ifstream svm_data( "E:/SVM_DATA.txt" );//首先,這裡搞一個檔案列表,把訓練樣本圖片的路徑都寫在這個txt檔案中,使用bat批處理檔案可以得到這個txt檔案
- unsigned
- while( svm_data )//將訓練樣本檔案依次讀取進來
- {
- if( getline( svm_data, buf ) )
- {
- nLine ++;
- if( nLine % 2 == 0 )//這裡的分類比較有意思,看得出來上面的SVM_DATA.txt文字中應該是一行是檔案路徑,接著下一行就是該圖片的類別,可以設定為0或者1,當然多個也無所謂
- {
- img_catg.push_back( atoi( buf.c_str() ) );//atoi將字串轉換成整型,標誌(0,1),注意這裡至少要有兩個類別,否則會出錯
- }
- else
- {
- img_path.push_back( buf );//影象路徑
- }
- }
- }
- svm_data.close();//關閉檔案
- CvMat *data_mat, *res_mat;
- int nImgNum = nLine / 2; //讀入樣本數量 ,因為是每隔一行才是圖片路徑,所以要除以2
- ////樣本矩陣,nImgNum:橫座標是樣本數量, WIDTH * HEIGHT:樣本特徵向量,即影象大小
- data_mat = cvCreateMat( nImgNum, 1764, CV_32FC1 ); //這裡第二個引數,即矩陣的列是由下面的descriptors的大小決定的,可以由descriptors.size()得到,且對於不同大小的輸入訓練圖片,這個值是不同的
- cvSetZero( data_mat );
- //型別矩陣,儲存每個樣本的型別標誌
- res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );
- cvSetZero( res_mat );
- IplImage* src;
- IplImage* trainImg=cvCreateImage(cvSize(64,64),8,3);//需要分析的圖片,這裡預設設定圖片是64*64大小,所以上面定義了1764,如果要更改圖片大小,可以先用debug檢視一下descriptors是多少,然後設定好再執行
- //開始搞HOG特徵
- for( string::size_type i = 0; i != img_path.size(); i++ )
- {
- src=cvLoadImage(img_path[i].c_str(),1);
- if( src == NULL )
- {
- cout<<" can not load the image: "<<img_path[i].c_str()<<endl;
- continue;
- }
- cout<<" processing "<<img_path[i].c_str()<<endl;
- cvResize(src,trainImg); //讀取圖片
- HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
- vector<float>descriptors;//結果陣列
- hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
- cout<<"HOG dims: "<<descriptors.size()<<endl;
- //CvMat* SVMtrainMat=cvCreateMat(descriptors.size(),1,CV_32FC1);
- n=0;
- for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
- {
- cvmSet(data_mat,i,n,*iter);//把HOG儲存下來
- n++;
- }
- //cout<<SVMtrainMat->rows<<endl;
- cvmSet( res_mat, i, 0, img_catg[i] );
- cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;
- }
- CvSVM svm = CvSVM();//新建一個SVM
- CvSVMParams param;//這裡是引數
- 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種類:CvSVM::C_SVC
- Kernel的種類:CvSVM::RBF
- degree:10.0(此次不使用)
- gamma:8.0
- coef0:1.0(此次不使用)
- C:10.0
- nu:0.5(此次不使用)
- p:0.1(此次不使用)
- 然後對訓練資料正規化處理,並放在CvMat型的數組裡。
- */
- //☆☆☆☆☆☆☆☆☆(5)SVM學習☆☆☆☆☆☆☆☆☆☆☆☆
- svm.train( data_mat, res_mat, NULL, NULL, param );//訓練啦
- //☆☆利用訓練資料和確定的學習引數,進行SVM學習☆☆☆☆
- svm.save( "SVM_DATA.xml" );
- //檢測樣本
- IplImage *test;
- vector<string> img_tst_path;
- ifstream img_tst( "E:/SVM_TEST.txt" );//同輸入訓練樣本,這裡也是一樣的,只不過不需要標註圖片屬於哪一類了
- while( img_tst )
- {
- if( getline( img_tst, buf ) )
- {
- img_tst_path.push_back( buf );
- }
- }
- img_tst.close();
- CvMat *test_hog = cvCreateMat( 1, 1764, CV_32FC1 );//注意這裡的1764,同上面一樣
- char line[512];
- ofstream predict_txt( "SVM_PREDICT.txt" );//把預測結果儲存在這個文字中
- for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍歷所有的待檢測圖片
- {
- test = cvLoadImage( img_tst_path[j].c_str(), 1);
- if( test == NULL )
- {
- cout<<" can not load the image: "<<img_tst_path[j].c_str()<<endl;
- continue;
- }
- cvZero(trainImg);
- cvResize(test,trainImg); //讀取圖片
- HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
- vector<float>descriptors;//結果陣列
- hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
- cout<<"HOG dims: "<<descriptors.size()<<endl;
- CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1);
- n=0;
- for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
- {
- cvmSet(SVMtrainMat,0,n,*iter);
- n++;
- }
- int ret = svm.predict(SVMtrainMat);//獲取最終檢測結果,這個predict的用法見 OpenCV的文件
- std::sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret );
- predict_txt<<line;
- }
- predict_txt.close();
- //cvReleaseImage( &src);
- //cvReleaseImage( &sampleImg );
- //cvReleaseImage( &tst );
- //cvReleaseImage( &tst_tmp );
- cvReleaseMat( &data_mat );
- cvReleaseMat( &res_mat );
- return 0;
- }
[cpp] view plaincopyprint
#include "cv.h"
#include "highgui.h"
#include "stdafx.h"
#include <ml.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
vector<string> img_path;//輸入檔名變數
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data( "E:/SVM_DATA.txt" );//首先,這裡搞一個檔案列表,把訓練樣本圖片的路徑都寫在這個txt檔案中,使用bat批處理檔案可以得到這個txt檔案
unsigned long n;
while( svm_data )//將訓練樣本檔案依次讀取進來
{
if( getline( svm_data, buf ) )
{
nLine ++;
if( nLine % 2 == 0 )//這裡的分類比較有意思,看得出來上面的SVM_DATA.txt文字中應該是一行是檔案路徑,接著下一行就是該圖片的類別,可以設定為0或者1,當然多個也無所謂
{
img_catg.push_back( atoi( buf.c_str() ) );//atoi將字串轉換成整型,標誌(0,1),注意這裡至少要有兩個類別,否則會出錯
}
else
{
img_path.push_back( buf );//影象路徑
}
}
}
svm_data.close();//關閉檔案
CvMat *data_mat, *res_mat;
int nImgNum = nLine / 2; //讀入樣本數量 ,因為是每隔一行才是圖片路徑,所以要除以2
////樣本矩陣,nImgNum:橫座標是樣本數量, WIDTH * HEIGHT:樣本特徵向量,即影象大小
data_mat = cvCreateMat( nImgNum, 1764, CV_32FC1 ); //這裡第二個引數,即矩陣的列是由下面的descriptors的大小決定的,可以由descriptors.size()得到,且對於不同大小的輸入訓練圖片,這個值是不同的
cvSetZero( data_mat );
//型別矩陣,儲存每個樣本的型別標誌
res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );
cvSetZero( res_mat );
IplImage* src;
IplImage* trainImg=cvCreateImage(cvSize(64,64),8,3);//需要分析的圖片,這裡預設設定圖片是64*64大小,所以上面定義了1764,如果要更改圖片大小,可以先用debug檢視一下descriptors是多少,然後設定好再執行
//開始搞HOG特徵
for( string::size_type i = 0; i != img_path.size(); i++ )
{
src=cvLoadImage(img_path[i].c_str(),1);
if( src == NULL )
{
cout<<" can not load the image: "<<img_path[i].c_str()<<endl;
continue;
}
cout<<" processing "<<img_path[i].c_str()<<endl;
cvResize(src,trainImg); //讀取圖片
HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
vector<float>descriptors;//結果陣列
hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
cout<<"HOG dims: "<<descriptors.size()<<endl;
//CvMat* SVMtrainMat=cvCreateMat(descriptors.size(),1,CV_32FC1);
n=0;
for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(data_mat,i,n,*iter);//把HOG儲存下來
n++;
}
//cout<<SVMtrainMat->rows<<endl;
cvmSet( res_mat, i, 0, img_catg[i] );
cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;
}
CvSVM svm = CvSVM();//新建一個SVM
CvSVMParams param;//這裡是引數
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種類:CvSVM::C_SVC
Kernel的種類:CvSVM::RBF
degree:10.0(此次不使用)
gamma:8.0
coef0:1.0(此次不使用)
C:10.0
nu:0.5(此次不使用)
p:0.1(此次不使用)
然後對訓練資料正規化處理,並放在CvMat型的數組裡。
*/
//☆☆☆☆☆☆☆☆☆(5)SVM學習☆☆☆☆☆☆☆☆☆☆☆☆
svm.train( data_mat, res_mat, NULL, NULL, param );//訓練啦
//☆☆利用訓練資料和確定的學習引數,進行SVM學習☆☆☆☆
svm.save( "SVM_DATA.xml" );
//檢測樣本
IplImage *test;
vector<string> img_tst_path;
ifstream img_tst( "E:/SVM_TEST.txt" );//同輸入訓練樣本,這裡也是一樣的,只不過不需要標註圖片屬於哪一類了
while( img_tst )
{
if( getline( img_tst, buf ) )
{
img_tst_path.push_back( buf );
}
}
img_tst.close();
CvMat *test_hog = cvCreateMat( 1, 1764, CV_32FC1 );//注意這裡的1764,同上面一樣
char line[512];
ofstream predict_txt( "SVM_PREDICT.txt" );//把預測結果儲存在這個文字中
for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍歷所有的待檢測圖片
{
test = cvLoadImage( img_tst_path[j].c_str(), 1);
if( test == NULL )
{
cout<<" can not load the image: "<<img_tst_path[j].c_str()<<endl;
continue;
}
cvZero(trainImg);
cvResize(test,trainImg); //讀取圖片
HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
vector<float>descriptors;//結果陣列
hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
cout<<"HOG dims: "<<descriptors.size()<<endl;
CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1);
n=0;
for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(SVMtrainMat,0,n,*iter);
n++;
}
int ret = svm.predict(SVMtrainMat);//獲取最終檢測結果,這個predict的用法見 OpenCV的文件
std::sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret );
predict_txt<<line;
}
predict_txt.close();
//cvReleaseImage( &src);
//cvReleaseImage( &sampleImg );
//cvReleaseImage( &tst );
//cvReleaseImage( &tst_tmp );
cvReleaseMat( &data_mat );
cvReleaseMat( &res_mat );
return 0;
}
其中,關於HOG函式HOGDescriptor,見部落格http://blog.csdn.net/raocong2010/article/details/6239431
另外,自己需要把這個程式嵌入到另外一個工程中去,因為那裡資料型別是Mat,不是cvMat,所以我又修改了上面的程式,並且圖片大小也不是固定的64*64,需要自己設定一下圖片大小,因為太懶,直接把改好的程式放過來:
[cpp] view plaincopyprint?- #include "stdafx.h"
- #include "cv.h"
- #include "highgui.h"
- #include "stdafx.h"
- #include <ml.h>
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <vector>
- usingnamespace cv;
- usingnamespace std;
- int main(int argc, char** argv)
- {
- int ImgWidht = 120;
- int ImgHeight = 120;
- vector<string> img_path;
- vector<int> img_catg;
- int nLine = 0;
- string buf;
- ifstream svm_data( "E:/apple/SVM_DATA.txt" );
- unsigned long n;
- while( svm_data )
- {
- if( getline( svm_data, buf ) )
- {
- nLine ++;
- if( nLine < 5 )
- {
- img_catg.push_back(1);
- img_path.push_back( buf );//影象路徑
- }
- else
- {
- img_catg.push_back(0);
- img_path.push_back( buf );//影象路徑
- }
- }
- }
- svm_data.close();//關閉檔案
- Mat data_mat, res_mat;
- int nImgNum = nLine; //讀入樣本數量
- ////樣本矩陣,nImgNum:橫座標是樣本數量, WIDTH * HEIGHT:樣本特徵向量,即影象大小
- //data_mat = Mat::zeros( nImgNum, 12996, CV_32FC1 );
- //型別矩陣,儲存每個樣本的型別標誌
- res_mat = Mat::zeros( nImgNum, 1, CV_32FC1 );
- Mat src;
- Mat trainImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3);//需要分析的圖片
- for( string::size_type i = 0; i != img_path.size(); i++ )
- {
- src = imread(img_path[i].c_str(), 1);
- cout<<" processing "<<img_path[i].c_str()<<endl;
- resize(src, trainImg, cv::Size(ImgWidht,ImgHeight), 0, 0, INTER_CUBIC);
- HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8), 9); //具體意思見參考文章1,2
- vector<float>descriptors;//結果陣列
- hog->compute(trainImg, descriptors, Size(1,1), Size(0,0)); //呼叫計算函式開始計算
- if (i==0)
- {
- data_mat = Mat::zeros( nImgNum, descriptors.size(), CV_32FC1 ); //根據輸入圖片大小進行分配空間
- }
- cout<<"HOG dims: "<<descriptors.size()<<endl;
- n=0;
- for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
- {
- data_mat.at<float>(i,n) = *iter;
- n++;
- }
- //cout<<SVMtrainMat->rows<<endl;
- res_mat.at<float>(i, 0) = img_catg[i];
- cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;
- }
- CvSVM svm = CvSVM();
- CvSVMParams param;
- 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種類:CvSVM::C_SVC
- Kernel的種類:CvSVM::RBF
- degree:10.0(此次不使用)
- gamma:8.0
- coef0:1.0(此次不使用)
- C:10.0
- nu:0.5(此次不使用)
- p:0.1(此次不使用)
- 然後對訓練資料正規化處理,並放在CvMat型的數組裡。
- */
- //☆☆☆☆☆☆☆☆☆(5)SVM學習☆☆☆☆☆☆☆☆☆☆☆☆
- svm.train( data_mat, res_mat, Mat(), Mat(), param );
- //☆☆利用訓練資料和確定的學習引數,進行SVM學習☆☆☆☆
- svm.save( "E:/apple/SVM_DATA.xml" );
- //檢測樣本
- vector<string> img_tst_path;
- ifstream img_tst( "E:/apple/SVM_TEST.txt" );
- while( img_tst )
- {
- if( getline( img_tst, buf ) )
- {
- img_tst_path.push_back( buf );
- }
- }
- img_tst.close();
- Mat test;
- char line[512];
- ofstream predict_txt( "E:/apple/SVM_PREDICT.txt" );
- for( string::size_type j = 0; j != img_tst_path.size(); j++ )
- {
- test = imread( img_tst_path[j].c_str(), 1);//讀入影象
- resize(test, trainImg, cv::Size(ImgWidht,ImgHeight), 0, 0, INTER_CUBIC);//要搞成同樣的大小才可以檢測到
- HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
- vector<float>descriptors;//結果陣列
- hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
- cout<<"The Detection Result:"<<endl;
- cout<<"HOG dims: "<<descriptors.size()<<endl;
- Mat SVMtrainMat = Mat::zeros(1,descriptors.size(),CV_32FC1);
- n=0;
- for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
- {
- SVMtrainMat.at<float>(0,n) = *iter;
- n++;
- }
- int ret = svm.predict(SVMtrainMat);
- std::sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret );
- printf("%s %d\r\n", img_tst_path[j].c_str(), ret);
- getchar();
- predict_txt<<line;
- }
- predict_txt.close();
- return 0;
- }
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "stdafx.h"
#include <ml.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
int ImgWidht = 120;
int ImgHeight = 120;
vector<string> img_path;
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data( "E:/apple/SVM_DATA.txt" );
unsigned long n;
while( svm_data )
{
if( getline( svm_data, buf ) )
{
nLine ++;
if( nLine < 5 )
{
img_catg.push_back(1);
img_path.push_back( buf );//影象路徑
}
else
{
img_catg.push_back(0);
img_path.push_back( buf );//影象路徑
}
}
}
svm_data.close();//關閉檔案
Mat data_mat, res_mat;
int nImgNum = nLine; //讀入樣本數量
////樣本矩陣,nImgNum:橫座標是樣本數量, WIDTH * HEIGHT:樣本特徵向量,即影象大小
//data_mat = Mat::zeros( nImgNum, 12996, CV_32FC1 );
//型別矩陣,儲存每個樣本的型別標誌
res_mat = Mat::zeros( nImgNum, 1, CV_32FC1 );
Mat src;
Mat trainImg = Mat::zeros(ImgHeight, ImgWidht, CV_8UC3);//需要分析的圖片
for( string::size_type i = 0; i != img_path.size(); i++ )
{
src = imread(img_path[i].c_str(), 1);
cout<<" processing "<<img_path[i].c_str()<<endl;
resize(src, trainImg, cv::Size(ImgWidht,ImgHeight), 0, 0, INTER_CUBIC);
HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8), 9); //具體意思見參考文章1,2
vector<float>descriptors;//結果陣列
hog->compute(trainImg, descriptors, Size(1,1), Size(0,0)); //呼叫計算函式開始計算
if (i==0)
{
data_mat = Mat::zeros( nImgNum, descriptors.size(), CV_32FC1 ); //根據輸入圖片大小進行分配空間
}
cout<<"HOG dims: "<<descriptors.size()<<endl;
n=0;
for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
data_mat.at<float>(i,n) = *iter;
n++;
}
//cout<<SVMtrainMat->rows<<endl;
res_mat.at<float>(i, 0) = img_catg[i];
cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;
}
CvSVM svm = CvSVM();
CvSVMParams param;
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種類:CvSVM::C_SVC
Kernel的種類:CvSVM::RBF
degree:10.0(此次不使用)
gamma:8.0
coef0:1.0(此次不使用)
C:10.0
nu:0.5(此次不使用)
p:0.1(此次不使用)
然後對訓練資料正規化處理,並放在CvMat型的數組裡。
*/
//☆☆☆☆☆☆☆☆☆(5)SVM學習☆☆☆☆☆☆☆☆☆☆☆☆
svm.train( data_mat, res_mat, Mat(), Mat(), param );
//☆☆利用訓練資料和確定的學習引數,進行SVM學習☆☆☆☆
svm.save( "E:/apple/SVM_DATA.xml" );
//檢測樣本
vector<string> img_tst_path;
ifstream img_tst( "E:/apple/SVM_TEST.txt" );
while( img_tst )
{
if( getline( img_tst, buf ) )
{
img_tst_path.push_back( buf );
}
}
img_tst.close();
Mat test;
char line[512];
ofstream predict_txt( "E:/apple/SVM_PREDICT.txt" );
for( string::size_type j = 0; j != img_tst_path.size(); j++ )
{
test = imread( img_tst_path[j].c_str(), 1);//讀入影象
resize(test, trainImg, cv::Size(ImgWidht,ImgHeight), 0, 0, INTER_CUBIC);//要搞成同樣的大小才可以檢測到
HOGDescriptor *hog=new HOGDescriptor(cvSize(ImgWidht,ImgHeight),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具體意思見參考文章1,2
vector<float>descriptors;//結果陣列
hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //呼叫計算函式開始計算
cout<<"The Detection Result:"<<endl;
cout<<"HOG dims: "<<descriptors.size()<<endl;
Mat SVMtrainMat = Mat::zeros(1,descriptors.size(),CV_32FC1);
n=0;
for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
SVMtrainMat.at<float>(0,n) = *iter;
n++;
}
int ret = svm.predict(SVMtrainMat);
std::sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret );
printf("%s %d\r\n", img_tst_path[j].c_str(), ret);
getchar();
predict_txt<<line;
}
predict_txt.close();
return 0;
}
就到這裡吧,再整理一下思路。
如果執行的時候出現Link錯誤,有可能是沒有附加依賴項,要新增opencv_objdetect230d.lib,我的OpenCV是2.3版本,所以這裡是230.
如下為評論整理(本人):
1、txt模板中的內容就是d:\img\1.jpg
2、CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
我在做分類的時候用的這個,但是出現: error C2653: “CvSVM”: 不是類或名稱空間名稱
解決辦法:CvSVM的標頭檔案是ml.h,你要確認你包含了這個檔案,你也可以再OpenCV裡找到這個檔案,我找了一下,看到裡面確實有定義這個class,我用的OpenCV版本 是2.3.1,另外,確認你有using namespace cv
3、通過批處理bat可以得到txt文件,按照如下
新建一個txt文件,輸入
dir /b/s/p/w *.jpg>train_list.txt
@pause
將檔案字尾改為bat
4、提問:樣本是怎麼取的呢?要是檢測人的時候,主把一個人的全身像扣下來?
回覆:樣本看你自己取的了,你訓練了什麼樣子的樣本,那麼測試的時候就只能測試哪個樣的。例如,如果你把人摳出來做樣本訓練,那麼當你檢測的時候你也必須要先把人從背景中摳出來然後再扔進去做檢測。把人從背景中摳出來可以排除背景的干擾,但是摳得不準確反而適得其反。
提問:和背景一塊兒訓練背景變了不是就也檢測不出來了?
回覆:對啊,如果你的訓練樣本中有沒有把背景剔除掉,做檢測的時候換了背景會有影響的,至於最終會有多大的影響就不好說了,如果你的訓練樣本夠大,也許可以抵消掉這種影響。我現在做的東西就是覺得去背景太困難了,就連同背景一起訓練了,最終效果也還好。
提問:你用了GPU了吧?解析度是多大的,這東東檢測的時候速度太慢了吧,如果只用CPU。
回覆:從來沒有用過GPU加速這種東西,也不用上,提取紋理的時候也許用的上。解析度很低,圖片最終大小差不多50*50。
5、如果正負總共兩千樣本的話,特徵數目我用的是672,訓練得到的分類器應該也就是最多幾十兆吧,不會超過50M的,我目前用的正負樣本總共有十萬,特徵向量維數是672,也就是160M
6、程式到 svm.train( data_mat, res_mat, Mat(), Mat(), param ); 就會跳出error:OpenCV Error:Bad arguments: <There is only a single class> in cvPreprocessCategoricalResponse,file..\..\..\src\opencv\modules\ml\src\inner_functions.cpp,line 729是形參啥的傳遞錯誤還是怎樣 ?
解決:應該是引數傳統有問題,你點繼續執行,看看呼叫堆疊哪裡出錯了,就是影象型別的分類 必須是兩種影象的 雖然我不是很懂為啥 但分成多個影象就 OK了。
7、txt中存放的是正負樣本,在這個txt文字中一行是圖片檔名,接著下一行就是這個圖片的類別。例如,第一行是一個圖片檔名,然後接著的第二行就是表示一下這個圖片屬於哪一類,可以設定為0或者1,然後第三行又是圖片檔名,然後第四行表示第三行的圖片類別,0或者1。你可以規定類別1是正樣本,0是負樣本,最後測試一張圖片,程式會告訴你這個圖片屬於1還是0。
8、實現:輸入一張同樣大小的圖判斷是否為正樣本對應的內容。
9、輸入的樣本(SVM_DATA.txt)不需要一個正樣本,一個負樣本交替,只需要路徑寫對即可。
10、提問:關於SVM_DATA.txt 內容問題,我也是按照這樣正負樣本來寫的txt文件:
D:\picture\1.bmp
0
D:\picture\2.bmp
1
但是在執行時出現了問題,提示無法載入影象1\0;但是已經載入的圖片生成了xml檔案
回覆:文件沒有寫對吧 路徑裡的"回車"和“\”寫混了
11、用hog提取了特徵後,我一共有2000張樣本,每張3758個特徵,由於特徵太大,無法將特徵存為矩陣,該怎樣解決
回覆:特徵依然儲存為矩陣形式,每一行儲存一張影象的N維特徵,對你來說就是建立一個3758x2000的矩陣
12、CvSVM::train的時候出現error:命令列顯示:OpenCV Error:Bad arguments: <There is only a single class> in cvPreprocessCategoricalResponse,file..\..\..\src\opencv\modules\ml\src\inner_functions.cpp,line 729,train的形參除錯下都是正確的
我的SVM_DATA.txt
D:\picture\1.bmp
0
D:\picture\2.bmp
1
回覆:訓練路徑文件裡的response寫的不對 就是對應的型別 而且應該至少包含兩種型別~,SVM_DATA.txt無錯,0或者1就是response 類別名
13、出現error C2065: 'HOGDescriptor' : undeclared identifier錯誤,增加#include "cvaux.h"標頭檔案可順利編譯
14、E:/SVM_TEST.txt的內容
路徑名,型別名,一行一行交替排列~!
D:/img/001.jpg
1
D:/img/002.jpg
1
D:/img/003.jpg
0
...
15、descriptors的作用就是儲存結果的特徵向量
16、提問:hog特徵檢測的輸入影象src 是什麼形式的呢?rgb或者灰度影象都支援吧 ?
IplImage* trainImg=cvCreateImage(cvSize(64,64),8,3);//需要分析的圖片
cvResize(src,trainImg); //讀取圖片
回覆:文件中hog檢測:CV_8UC1 and CV_8UC4 types are supported for now 一到四通道整型都支援。
17、svm.save( "SVM_DATA.xml" ); 這個儲存XML檔案的函式是OpenCV自帶的。。。