如何训练opencv hog.detectmultiscale 的分类器

下面的程序亲自测试成功,但是其实不用这么麻烦的:


#include "opencv2/opencv.hpp"

#include "windows.h"

#include "fstream"

#include <iostream>

 using namespace std;

 using namespace cv;

 class Mysvm: public CvSVM

 {

  public:

     int get_alpha_count()

     {

         return this->sv_total;

     }

 

     int get_sv_dim()

     {

          return this->var_all;

     }

 

      int get_sv_count()

      {

          return this->decision_func->sv_count;

     }



    double* get_alpha()

    {

         return this->decision_func->alpha;

    }



      float** get_sv()

      {

          return this->sv;

     }

  

      float get_rho()

      {

          return this->decision_func->rho;

      }


  };

  

  int my_train()

  {

  

      /*-----------------------------------------------------------------------------

      *  d:/pedestrianDetect-peopleFlow.txt是用来保存所有样本的特点,大小为样本数*3780(每个样本的特点数)

      *d:/pedestrianDetect-peopleFlow.txt是用来保存所有样本的特点,大小为样本数*1764(每个样本的特点数)

     *

      *

      *

      *-----------------------------------------------------------------------------*/

     char classifierSavePath[256] = "d:/pedestrianDetect-peopleFlow.txt";

     string buf;

    vector<string> pos_img_path;

     vector<string> neg_img_path;

      ifstream svm_pos_data("pos.txt");           /* 批处理惩罚法度生成 */

     ifstream svm_neg_data("neg.txt");           /* 批处理惩罚生成 */

   while( svm_pos_data )//将练习样本文件依次读取进来    

     {    

         if( getline( svm_pos_data, buf ) )

            pos_img_path.push_back( buf );



    }

    while( svm_neg_data )//将练习样本文件依次读取进来    

    {    

         if( getline( svm_neg_data, buf ) )

              neg_img_path.push_back( buf );

  

      }

      cout<<pos_img_path.size()<<"个正样本"<<endl;

      cout<<neg_img_path.size()<<"个负样本"<<endl;

      int totalSampleCount=pos_img_path.size()+neg_img_path.size();

     // CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 3780, CV_32FC1);
	   CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 1764, CV_32FC1);
      //64*128窗口大小的练习样本,该矩阵将是totalSample*3780

     //64*64的窗口大小的练习样本,该矩阵将是totalSample*1764

      cvSetZero(sampleFeaturesMat);  

      CvMat *sampleLabelMat = cvCreateMat(totalSampleCount, 1, CV_32FC1);//样本标识  

      cvSetZero(sampleLabelMat);  

 

      cout<<"************************************************************"<<endl;

    cout<<"start to training positive samples..."<<endl;

 

     

    
     for(int i=0; i<pos_img_path.size(); i++)  
     {  

         cv::Mat img1 = cv::imread(pos_img_path.at(i));
		 Mat img;
		 resize(img1,img,Size(64,64));
    

         if( img.data == NULL )

         {

             cout<<"positive image sample load error: "<<i<<endl;

             system("pause");

             continue;

        }

 

         //cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
		 cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);

         vector<float> featureVec; 

 

         hog.compute(img, featureVec, cv::Size(8,8));  

         unsigned int featureVecSize = featureVec.size();
 

         for (int j=0; j<featureVecSize; j++)  

         {          

            CV_MAT_ELEM( *sampleFeaturesMat, float, i, j ) = featureVec[j]; 

         }  

         sampleLabelMat->data.fl[i] = 1;

     }

     cout<<"end of training for positive samples..."<<endl;

 

  cout<<"*********************************************************"<<endl;

    cout<<"start to train negative samples..."<<endl;

    

     for (int i=0; i<neg_img_path.size(); i++)

    {  

        

        cv::Mat img1 = cv::imread(neg_img_path.at(i));
			Mat img;
		 resize(img1,img,Size(64,64));

        if(img.data == NULL)

        {

             cout<<"negative image sample load error: "<<endl;

             continue;

        }


      // cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);  
	   cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);  

         vector<float> featureVec; 



       hog.compute(img,featureVec,cv::Size(8,8));//策画HOG特点

         int featureVecSize = featureVec.size();  



         for ( int j=0; j<featureVecSize; j ++)  

        {  

             CV_MAT_ELEM( *sampleFeaturesMat, float, i + pos_img_path.size(), j ) = featureVec[j];

         }  

 

         sampleLabelMat->data.fl[ i + pos_img_path.size() ] = -1;

     }  

 

     cout<<"end of training for negative samples..."<<endl;

    cout<<"********************************************************"<<endl;

     cout<<"start to train for SVM classifier..."<<endl;

 

     CvSVMParams params;  

     params.svm_type = CvSVM::C_SVC;  

     params.kernel_type = CvSVM::LINEAR;  

   params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON);

     params.C = 0.01;

 

     Mysvm svm;

    svm.train( sampleFeaturesMat, sampleLabelMat, NULL, NULL, params ); //用SVM线性分类器练习

    svm.save(classifierSavePath);


     cvReleaseMat(&sampleFeaturesMat);
     cvReleaseMat(&sampleLabelMat);

     int supportVectorSize = svm.get_support_vector_count();
     cout<<"support vector size of SVM:"<<supportVectorSize<<endl;

    cout<<"************************ end of training for SVM ******************"<<endl;

 

     CvMat *sv,*alp,*re;//所有样本特点向量 

     //sv  = cvCreateMat(supportVectorSize , 3780, CV_32FC1);

	  sv  = cvCreateMat(supportVectorSize , 1764, CV_32FC1);

    alp = cvCreateMat(1 , supportVectorSize, CV_32FC1);

     //re  = cvCreateMat(1 , 3780, CV_32FC1);

	 re  = cvCreateMat(1 , 1764, CV_32FC1);

     CvMat *res  = cvCreateMat(1 , 1, CV_32FC1);

 

     cvSetZero(sv);

     cvSetZero(re);

 

     for(int i=0; i<supportVectorSize; i++)

     {

        //memcpy( (float*)(sv->data.fl+i*3780), svm.get_support_vector(i), 3780*sizeof(float));    
		memcpy( (float*)(sv->data.fl+i*1764), svm.get_support_vector(i), 1764*sizeof(float));    

     }

 

    double* alphaArr = svm.get_alpha();

     int alphaCount = svm.get_alpha_count();



     for(int i=0; i<supportVectorSize; i++)

    {

        alp->data.fl[i] = (float)alphaArr[i];

     }

     cvMatMul(alp, sv, re);



   int posCount = 0;

    // for (int i=0; i<3780; i++)

    //{

    //     re->data.fl[i] *= -1;

    // }

	      for (int i=0; i<1764; i++)

    {

         re->data.fl[i] *= -1;

     }

 

    /*-----------------------------------------------------------------------------

      *  d:/hogSVMDetector-peopleFlow.txt文件中保存的是支撑向量,共有3781个值,是一个3781*1的列向量

      *d:/hogSVMDetector-peopleFlow.txt文件中保存的是支撑向量,共有1764个值,是一个3781*1的列向量

     *

     *-----------------------------------------------------------------------------*/

    FILE* fp = fopen("d:/hogSVMDetector-peopleFlow.txt","wb");

     if( NULL == fp )

     {

         return 1;

    }

    // for(int i=0; i<3780; i++)

    //{

    //     fprintf(fp,"%f \n",re->data.fl[i]);

    // }

	      for(int i=0; i<1764; i++)

    {

         fprintf(fp,"%f \n",re->data.fl[i]);

     }

    float rho = svm.get_rho();

    fprintf(fp, "%f", rho);

     cout<<"d:/hogSVMDetector.txt 保存完毕"<<endl;//保存HOG能识此外分类器

     fclose(fp);

 

     return 1;

 }

 void my_detect()

 {

    CvCapture* cap = cvCreateFileCapture("E:\\test.avi");

    if (!cap)

     {

         cout<<"avi file load error..."<<endl;

         system("pause");

         exit(-1);

     }

 

     vector<float> x;

     ifstream fileIn("e:/hogSVMDetector-peopleFlow.txt", ios::in);

     float val = 0.0f;

     while(!fileIn.eof())

     {

         fileIn>>val;

         x.push_back(val);

     }

     fileIn.close();

 

    vector<cv::Rect>  found;

     cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);

     

    /*-----------------------------------------------------------------------------

     *

     *

      *  若是setSVMDetector呈现题目的话,可能是这个原因:因为默认hog.getDefaultPeopleDetector()

      *  获取的检测器的大小是3781*1的列向量,所以若是生成的e:/hogSVMDetector-peopleFlow.txt里的大小不等的话

      *  ,读入

     *  就会呈现错误,可能这个函数推敲了运行的速度题目,所以限制了大小为3781*1

      *  

      *  希罕重视:有些童鞋可能生成的特点向量是15876(所以setSVMDetector里的列向量就是15877了与默认的大小不一,assetion就失足了)

      *  ,只要调剂下图像的大小和检测窗口的大小,使生成的特点向量为3780就行了,怎么策画,可以参考

      *  网上其他博客

      *

      *-----------------------------------------------------------------------------*/

    hog.setSVMDetector(x);

 

     IplImage* img = NULL;

    cvNamedWindow("img", 0);

     while(img=cvQueryFrame(cap))

    {

         hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);

         if (found.size() > 0)

         {

             for (int i=0; i<found.size(); i++)

             {

                CvRect tempRect = cvRect(found[i].x, found[i].y, found[i].width, found[i].height);



                 cvRectangle(img, cvPoint(tempRect.x,tempRect.y),

                    cvPoint(tempRect.x+tempRect.width,tempRect.y+tempRect.height),CV_RGB(255,0,0), 2);

             }

         }

     }

     cvReleaseCapture(&cap);

 }

 
#include<fstream>

 int main(int argc, char** argv){



     //my_train();

     //my_detect();

     vector<float> x;

     ifstream fileIn("d:/hogSVMDetector-peopleFlow.txt", ios::in); /* 读入支撑向量,没须要读入样本的向量 */

     float val = 0.0f;

     while(!fileIn.eof())

     {

        fileIn>>val;

         x.push_back(val);

     }

     fileIn.close();

 

    vector<Rect> found, found_filtered;

    // cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
	 cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);

     hog.setSVMDetector(x);

 

     Mat img;

    img=imread("d:/TEMP1/00281.jpg",1);

     hog.detectMultiScale(img, found, 0, cv::Size(2,2), cv::Size(1,1), 1.05, 2);

     size_t i, j;

     for( i = 0; i < found.size(); i++ )

    {

         Rect r = found[i];

         for( j = 0; j < found.size(); j++ )

             if( j != i && (r & found[j]) == r)

                 break;

         if( j == found.size() )

             found_filtered.push_back(r);

    }

    for( i = 0; i < found_filtered.size(); i++ )

     {

         Rect r = found_filtered[i];

        // the HOG detector returns slightly larger rectangles than the real objects.

        // so we slightly shrink the rectangles to get a nicer output.

         r.x += cvRound(r.width*0.1);

         r.width = cvRound(r.width*0.8);

         r.y += cvRound(r.height*0.07);

         r.height = cvRound(r.height*0.8);

         rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);

     }

     imshow("people detector", img);

     waitKey();



     /*cvNamedWindow("img", 0);

     string testimage="E:\database\picture_resize_pos\resize000r.bmp";

     Mat img=cv::imread(testimage);

     hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);

     if (found.size() > 0)

     {

     printf("found!");

     }*/

       

    return 0;



 }



看了代码发现,其实就是将训练好的XML文件里面的 SV (支持向量)乘以alpha(对应的系数) 再加上rho(偏置) 存在一个txt 中

比如说:

 cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
   生成的hog特征是1764维,sv是N*1764 维        但是因为是线性核,所以N维向量可以对应乘完相加 ,得到一个1*1764的向量    最后保存 一个偏置

SVM函数f(x) = W*SV*A+B     其中(W为alpha,SV支持向量,A为样本的HOG特征,B为偏置) 

注意:偏置项保存在最后要取反的(也就是要加负号)。


//img为输入待检测的图片;found为检测到目标区域列表;参数3为程序内部计算为行人目标的阈值,也就是检测到的特征到SVM分类超平面的距离;
    //参数4为滑动窗口每次移动的距离。它必须是块移动的整数倍;参数5为图像扩充的大小;参数6为比例系数,即测试图片每次尺寸缩放增加的比例;
    //参数7为组阈值,即校正系数,当一个目标被多个窗口检测出来时,该参数此时就起了调节作用,为0时表示不起调节作用。
    hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);





猜你喜欢

转载自blog.csdn.net/yeyang911/article/details/17790785
今日推荐