opencv中应用HOG特征训练SVM多分类器的一般框架

1.HOG特征提取

opencv里关于HOG特征的提取是通过函数HOGDescriptor()来完成的,主要有下面4个构造函数:

CV_WRAP HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8),  
    cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1),  
    histogramNormType(HOGDescriptor::L2Hys), L2HysThreshold(0.2), gammaCorrection(true),   
    nlevels(HOGDescriptor::DEFAULT_NLEVELS)  
{} 

CV_WRAP HOGDescriptor(Size _winSize, Size _blockSize, Size _blockStride,  
              Size _cellSize, int _nbins, int _derivAperture=1, double _winSigma=-1,  
              int _histogramNormType=HOGDescriptor::L2Hys,  
              double _L2HysThreshold=0.2, bool _gammaCorrection=false,  
              int _nlevels=HOGDescriptor::DEFAULT_NLEVELS)  
: winSize(_winSize), blockSize(_blockSize), blockStride(_blockStride), cellSize(_cellSize),  
nbins(_nbins), derivAperture(_derivAperture), winSigma(_winSigma),  
histogramNormType(_histogramNormType), L2HysThreshold(_L2HysThreshold),  
gammaCorrection(_gammaCorrection), nlevels(_nlevels)  
{} 


CV_WRAP HOGDescriptor(const String& filename)  
{  
    load(filename);  
}

HOGDescriptor(const HOGDescriptor& d)  
{  
    d.copyTo(*this);  
}

实际应用过程中主要是第二个,其中有几个关键的参数:
  • winSize: 窗口的大小
  • blockSize:块的大小
  • blockStride:块滑动的增量
  • cellSize:元组的大小
  • nbins:梯度方向的数组,例如nBins=9时,在一个胞元内统计9个方向的梯度直方图,每个方向为180/9=20度。
实际应用中关键是弄清楚HOG特征的维数的计算,例如出入一幅64*64的图像,输出的结果就是一个很长的hog特征向量,向量的维度与上面的几个参数有关。例如按照第一个构造函数中默认的初始序列,可以计算得出hog的特征向量维度是:9*(16/8)*(16/8)*[(64-16)/8+1]*[(128-16)/8+1]=3780

size_t HOGDescriptor::getDescriptorSize() const  
{  
    CV_Assert(blockSize.width % cellSize.width == 0 &&  
        blockSize.height % cellSize.height == 0);  
    CV_Assert((winSize.width - blockSize.width) % blockStride.width == 0 &&  
        (winSize.height - blockSize.height) % blockStride.height == 0 );  
    return (size_t)nbins*  
        (blockSize.width/cellSize.width)*  
        (blockSize.height/cellSize.height)*  
        ((winSize.width - blockSize.width)/blockStride.width + 1)*  
        ((winSize.height - blockSize.height)/blockStride.height + 1);  
} 


详情关于HOG的理解可见:
http://blog.csdn.net/zouxy09/article/details/7929348/
http://blog.csdn.net/raodotcong/article/details/6239431

2.提取HOG特征,进行SVM训练分类的流程
  • 首先得有训练样本集和测试样本集,通常情况下,样本集中的样本的信息都是保存在文本文件中方便读取。通常情况下,如果样本的数量比较多,需要用bat批处理程序来提取文件名信息:dir /b/s/p/w *.jpg>train_list.txt    新建txt文档,将其保存为.bat文件,用Notepad保存比较方便。
  • 考虑到样本集一般比较多,数量也未知,一般需要用到STL中的vector
  • opencv中SVM的使用可以参考官方文档:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html

源码:
#include "cv.h"  
#include "highgui.h"  
#include   
#include   
#include   
#include   
#include   
using namespace cv;  
using namespace std;  
  
int main()    
{    
	int ImgWidht = 64;
	int ImgHeight = 64;
    vector img_path;  
    vector img_catg;  
    int nLine = 0;  
    string buf;  
    ifstream svm_data( "tran.txt" );  
    unsigned long n;  
  
    while( svm_data )  
    {  
        if( getline( svm_data, buf ) )  
        {  
            //三种类别,前10个,中间10个,最后10个
            if( nLine <10 )  
            {  
				img_catg.push_back(0);//图像类别
				img_path.push_back( buf );//图像路径 
            }  
            else  if(nLine <20 )
            {  
				img_catg.push_back(1);
				img_path.push_back( buf );//图像路径 
            } 
			else
			{
				img_catg.push_back(2);
				img_path.push_back( buf );//图像路径 
			}
			nLine ++;  
        }  
    }  
    svm_data.close();//关闭文件  
  
    Mat data_mat, res_mat;  
    int nImgNum = nLine;            //读入样本数量  
    //样本矩阵,nImgNum:行数代表样本的数量,每一行就是由一张图片计算得到HOG的特征向量,
	data_mat = Mat::zeros( nImgNum, 1764, CV_32FC1 ); //HOG特征的位数: 9*(16/8)*(16/8)*[(64-16)/8+1]*[(64-16)/8+1]=1764
    //类型矩阵,存储每个样本的类型标志  
    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 "<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: "<::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)  
        {  
			data_mat.at(i,n) = *iter;  
            n++;  
        }  
        //cout<rows<(i, 0) =  img_catg[i];  
        cout<<" end processing "< img_tst_path;  
    ifstream img_tst( "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( "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);  //窗口大小,块大小,块滑动增量,cell的大小,bins的个数
        vectordescriptors;//结果数组     
        hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //调用计算函数开始计算 
		cout<<"The Detection Result:"<::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)  
        {  
			SVMtrainMat.at(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);//输出预测的结果,ret的值就代表类别
		//getchar();
        predict_txt<


结果:

opencv中应用HOG特征训练SVM多分类器的一般框架_第1张图片





你可能感兴趣的:(计算机视觉)