SVM+HOG:训练分类器生成.xml文件

来源:互联网 发布:cm和魔趣哪个优化好点 编辑:程序博客网 时间:2024/06/04 19:53

Github:
https://github.com/icsfy/Pedestrian_Detection/blob/master/MORE.md

转载:http://blog.csdn.net/masibuaa/article/details/16105073

正样本来源是INRIA数据集中的96*160大小的人体图片,使用时上下左右都去掉16个像素,截取中间的64*128大小的人体。

负样本是从不包含人体的图片中随机裁取的,大小同样是64*128(从完全不包含人体的图片中随机剪裁出64*128大小的用于人体检测的负样本)。http://blog.csdn.net/gojawee/article/details/72828371

训练好的SVM分类器保存为XML文件,然后根据其中的支持向量和参数生成OpenCV中的HOG描述子可用的检测子参数,再调用OpenCV中的多尺度检测函数进行行人检测。

难例(Hard Example)是指利用第一次训练的分类器在负样本原图(肯定没有人体)上进行行人检测时所有检测到的矩形框,这些矩形框区域很明显都是误报,把这些误报的矩形框保存为图片,加入到初始的负样本集合中,重新进行SVM的训练,可显著减少误报。
http://blog.csdn.net/GoJawee/article/details/72845508

训练和检测的代码:

#include <iostream>  #include <fstream>  #include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  #include <opencv2/imgproc/imgproc.hpp>  #include <opencv2/objdetect/objdetect.hpp>  #include <opencv2/ml/ml.hpp>  using namespace std;  using namespace cv;  #define PosSamNO 2400     //正样本个数  #define NegSamNO 12000    //负样本个数  #define TRAIN true    //是否进行训练,true表示重新训练,false表示读取xml文件中的SVM模型  #define CENTRAL_CROP true   //true:训练时,对96*160的INRIA正样本图片剪裁出中间的64*128大小人体  //HardExample:负样本个数。如果HardExampleNO大于0,表示处理完初始负样本集后,继续处理HardExample负样本集。  //不使用HardExample时必须设置为0,因为特征向量矩阵和特征类别矩阵的维数初始化时用到这个值  #define HardExampleNO  0    //继承自CvSVM的类,因为生成setSVMDetector()中用到的检测子参数时,需要用到训练好的SVM的decision_func参数,  //但通过查看CvSVM源码可知decision_func参数是protected类型变量,无法直接访问到,只能继承之后通过函数访问  class MySVM : public CvSVM  {  public:      //获得SVM的决策函数中的alpha数组      double * get_alpha_vector()      {          return this->decision_func->alpha;      }      //获得SVM的决策函数中的rho参数,即偏移量      float get_rho()      {          return this->decision_func->rho;      }  };  int main()  {      //检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9      HOGDescriptor hog(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);//HOG检测器,用来计算HOG描述子的      int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定      MySVM svm;//SVM分类器      //若TRAIN为true,重新训练分类器      if(TRAIN)      {          string ImgName;//图片名(绝对路径)          ifstream finPos("F:\\dataset\\pos\\pos.txt");//正样本图片的文件名列表          ifstream finNeg("F:\\dataset\\neg\\neg.txt");//负样本图片的文件名列表          Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数              Mat sampleLabelMat;//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人          //依次读取正样本图片,生成HOG描述子          for(int num=0; num<PosSamNO && getline(finPos,ImgName); num++)          {              cout<<"处理:"<<ImgName<<endl;  //ImgName是全路径名             Mat src = imread(ImgName);//读取图片              if(CENTRAL_CROP)                  src = src(Rect(16,16,64,128));//将96*160的INRIA正样本图片剪裁为64*128,即剪去上下左右各16个像素              //resize(src,src,Size(64,128));              vector<float> descriptors;//HOG描述子向量              hog.compute(src,descriptors,Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)              //cout<<"描述子维数:"<<descriptors.size()<<endl;              //处理第一个样本时初始化特征向量矩阵和类别矩阵,因为只有知道了特征向量的维数才能初始化特征向量矩阵              if( 0 == num )              {                  DescriptorDim = descriptors.size();//HOG描述子的维数                  //初始化所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数sampleFeatureMat                  sampleFeatureMat = Mat::zeros(PosSamNO+NegSamNO+HardExampleNO, DescriptorDim, CV_32FC1);                  //初始化训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人                  sampleLabelMat = Mat::zeros(PosSamNO+NegSamNO+HardExampleNO, 1, CV_32FC1);              }              //将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat              for(int i=0; i<DescriptorDim; i++)                  sampleFeatureMat.at<float>(num,i) = descriptors[i];//第num个样本的特征向量中的第i个元素              sampleLabelMat.at<float>(num,0) = 1;//正样本类别为1,有人          }          //依次读取负样本图片,生成HOG描述子          for(int num=0; num<NegSamNO && getline(finNeg,ImgName); num++)          {              cout<<"处理:"<<ImgName<<endl;              Mat src = imread(ImgName);//读取图片              //resize(src,img,Size(64,128));              vector<float> descriptors;//HOG描述子向量              hog.compute(src,descriptors,Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)              //cout<<"描述子维数:"<<descriptors.size()<<endl;              //将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat              for(int i=0; i<DescriptorDim; i++)                  sampleFeatureMat.at<float>(num+PosSamNO,i) = descriptors[i];//第PosSamNO+num个样本的特征向量中的第i个元素              sampleLabelMat.at<float>(num+PosSamNO,0) = -1;//负样本类别为-1,无人          }          //处理HardExample负样本          if(HardExampleNO > 0)          {              ifstream finHardExample("F:\\dataset\\HardExample\\HardExample.txt");//HardExample负样本的文件名列表              //依次读取HardExample负样本图片,生成HOG描述子              for(int num=0; num<HardExampleNO && getline(finHardExample,ImgName); num++)              {                  cout<<"处理:"<<ImgName<<endl;                  Mat src = imread(ImgName);//读取图片                  //resize(src,img,Size(64,128));                  vector<float> descriptors;//HOG描述子向量                  hog.compute(src,descriptors,Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)                  //cout<<"描述子维数:"<<descriptors.size()<<endl;                  //将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat                  for(int i=0; i<DescriptorDim; i++)                      sampleFeatureMat.at<float>(num+PosSamNO+NegSamNO,i) = descriptors[i];//第PosSamNO+num个样本的特征向量中的第i个元素                  sampleLabelMat.at<float>(num+PosSamNO+NegSamNO,0) = -1;//负样本类别为-1,无人              }          }          ////输出样本的HOG特征向量矩阵到文件          //ofstream fout("SampleFeatureMat.txt");          //for(int i=0; i<PosSamNO+NegSamNO; i++)          //{          //  fout<<i<<endl;          //  for(int j=0; j<DescriptorDim; j++)          //      fout<<sampleFeatureMat.at<float>(i,j)<<"  ";          //  fout<<endl;          //}          //训练SVM分类器          //迭代终止条件,当迭代满1000次或误差小于FLT_EPSILON时停止迭代          CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON);          //SVM参数:SVM类型为C_SVC;线性核函数;松弛因子C=0.01          CvSVMParams param(CvSVM::C_SVC, CvSVM::LINEAR, 0, 1, 0, 0.01, 0, 0, 0, criteria);          cout<<"开始训练SVM分类器"<<endl;          svm.train(sampleFeatureMat, sampleLabelMat, Mat(), Mat(), param);//训练分类器          cout<<"训练完成"<<endl;          svm.save("F:\\dataset\\SVM_HOG.xml");//将训练好的SVM模型保存为xml文件      }      else //若TRAIN为false,从XML文件读取训练好的分类器      {          svm.load("F:\\dataset\\SVM_HOG.xml");//从XML文件读取训练好的SVM模型      }      /*************************************************************************************************     线性SVM训练完成后得到的XML文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;     将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个列向量。之后,再该列向量的最后添加一个元素rho。     如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),     就可以利用你的训练样本训练出来的分类器进行行人检测了。     ***************************************************************************************************/      DescriptorDim = svm.get_var_count();//特征向量的维数,即HOG描述子的维数      int supportVectorNum = svm.get_support_vector_count();//支持向量的个数      cout<<"支持向量个数:"<<supportVectorNum<<endl;      Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);//alpha向量,长度等于支持向量个数      Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);//支持向量矩阵      Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);//alpha向量乘以支持向量矩阵的结果      //将支持向量的数据复制到supportVectorMat矩阵中      for(int i=0; i<supportVectorNum; i++)      {          const float * pSVData = svm.get_support_vector(i);//返回第i个支持向量的数据指针          for(int j=0; j<DescriptorDim; j++)          {              supportVectorMat.at<float>(i,j) = pSVData[j];          }      }      //将alpha向量的数据复制到alphaMat中      double * pAlphaData = svm.get_alpha_vector();//返回SVM的决策函数中的alpha向量      for(int i=0; i<supportVectorNum; i++)      {          alphaMat.at<float>(0,i) = pAlphaData[i];      }      //计算-(alphaMat * supportVectorMat),结果放到resultMat中      //gemm(alphaMat, supportVectorMat, -1, 0, 1, resultMat);//不知道为什么加负号?      resultMat = -1 * alphaMat * supportVectorMat;      //得到最终的setSVMDetector(const vector<float>& detector)参数中可用的检测子      vector<float> myDetector;      //将resultMat中的数据复制到数组myDetector中      for(int i=0; i<DescriptorDim; i++)      {          myDetector.push_back(resultMat.at<float>(0,i));      }      //最后添加偏移量rho,得到检测子      myDetector.push_back(svm.get_rho());      cout<<"检测子维数:"<<myDetector.size()<<endl;      //设置HOGDescriptor的检测子      HOGDescriptor myHOG;      myHOG.setSVMDetector(myDetector);      //myHOG.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());      //保存检测子参数到文件      ofstream fout("F:\\dataset\\HOGDetectorForOpenCV.txt");      for(int i=0; i<myDetector.size(); i++)      {          fout<<myDetector[i]<<endl;      }      /**************读入图片进行HOG行人检测******************/      Mat src = imread("Test.jpg");      vector<Rect> found, found_filtered;//矩形框数组      cout<<"进行多尺度HOG人体检测"<<endl;      myHOG.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);//对图片进行多尺度行人检测      cout<<"找到的矩形框个数:"<<found.size()<<endl;      //找出所有没有嵌套的矩形框r,并放入found_filtered中,如果有嵌套的话,则取外面最大的那个矩形框放入found_filtered中      for(int i=0; i < found.size(); i++)      {          Rect r = found[i];          int j=0;          for(; j < found.size(); j++)              if(j != i && (r & found[j]) == r)                  break;          if( j == found.size())              found_filtered.push_back(r);      }      //画矩形框,因为hog检测出的矩形框比实际人体框要稍微大些,所以这里需要做一些调整      for(int i=0; i<found_filtered.size(); i++)      {          Rect r = found_filtered[i];          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(src, r.tl(), r.br(), Scalar(0,255,0), 3);      }      //imwrite("ImgProcessed.jpg",src);      namedWindow("src",0);      imshow("src",src);      waitKey(0);//注意:imshow之后必须加waitKey,否则无法显示图像      ///******************读入单个64*128的测试图并对其HOG描述子进行分类*********************/      ////读取测试图片(64*128大小),并计算其HOG描述子      //Mat testImg = imread("noperson000026.jpg");      //vector<float> descriptor;      //hog.compute(testImg,descriptor,Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)      //Mat testFeatureMat = Mat::zeros(1,3780,CV_32FC1);//测试样本的特征向量矩阵      ////将计算好的HOG描述子复制到testFeatureMat矩阵中      //for(int i=0; i<descriptor.size(); i++)      //  testFeatureMat.at<float>(0,i) = descriptor[i];      ////用训练好的SVM分类器对测试图片的特征向量进行分类      //int result = svm.predict(testFeatureMat);//返回类标      //cout<<"分类结果:"<<result<<endl;      system("pause");  }  

参考:http://blog.csdn.net/carson2005/article/details/7841443

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 跳了把腰伤了怎么办 爸爸对妈妈家暴怎么办 逆反心强23岁怎么办 觉得自己心理有问题怎么办 小孩心理脆弱过于敏感怎么办? 父母老是骂打我怎么办 爸妈打架闹离婚怎么办 夫妻离婚后孩子户口怎么办 离婚后孩子户口怎么办落户 50岁父母要离婚怎么办 父母离婚小孩没有出生证该怎么办 离婚。父母一直在劝说该怎么办 老婆跟人跑了怎么办啊 父母50了要离婚怎么办 父母吵架了我该怎么办 父母看孩子总是吵架怎么办 20岁父母离婚我怎么办 碰到没素质的人怎么办 父母抛弃了我该怎么办 父母说家里没钱困难怎么办 遇到素质低的老婆怎么办 孩子考试心里素质差怎么办 5岁儿童脾气不好怎么办 有一个素质差的父母怎么办 孩子对什么都无所谓怎么办 孩子在学习上无所谓怎么办 孩子对学习无所谓的态度怎么办 孩子不上进什么都无所谓怎么办 倔强的学生不理老师怎么办 一岁宝宝特别犟怎么办 孩子遇到问题喜欢发脾气怎么办 企业培养新人跑了怎么办 二年级学生读不懂题目怎么办 6岁宝宝有鼻炎怎么办 外地儿童怎么办北京医保卡 江苏联宝投资的钱怎么办 银行叫开了证券怎么办 中班心理健康我不开心了怎么办 大学生心理健康课总是抢不到怎么办 孩子成绩提不上去怎么办 孩子数学不开窍怎么办 二年级