帮助曾经像自己一样的小白,快速了解hog和svm,从而学会运用这两个算法来做些简单的行人检测
2017-04-11 20:38
453 查看
主题是帮助曾经像自己一样的小白,快速了解hog和svm,从而学会运用这两个算法来做些简单的行人检测。
那个我是天津理工大学的一名本科学生,2019届。有幸在大一考完C语言之后呢,碰到了学院的一位老师,他是做计算机视觉的,然后经过很久的积累,开始走上了简单的计算机视觉之路,就是opencv。说这么多就是让大家知道,opencv不难,难的是坚持,为自己的目标所坚持。
简单的看完毛星云的opencv3.0(那个3.0和2.0确实很多不一样,有时为了看csdn博客的以前的人做的好东西得不断得改为别人对应的版本。)学到最后简单的opencv知识是不够的,所以得了解机器学习有关得知识,从而使opencv更加智能
书籍推荐李航老师的“统计学习法”偏向数学证明为主,需要高数,线代,还有概率论的知识,可以看到不会时再从头找书看看相关的,例如什么是范数,什么是正定矩阵。。。
周志华老师的西瓜书“机器学习”偏形象,但是有时候却难理解
好了,回到主题是快速了解hog和svm
先了解svm支持向量机
建议点击看看http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms
线性的话,就是找出一条线将样本分为正样本和负样本,公式为y=wx+b,y的结果只为1或-1(1为正样本,-1为负样本)其中w,x是矩阵,也是向量,所以wx是向量的内积。
------------------------------------------------------------------------------------------------------------------
下面了解hog特征
建议点击看看http://blog.csdn.net/liulina603/article/details/8291093
总结:hog就是图片的一种特征,刚好很适合做人体检测而已
在2005年CVPR上,来自法国的研究人员Navneet Dalal 和Bill Triggs提出利用Hog进行特征提取,利用线性SVM作为分类器,从而实现行人检测。而这两位也通过大量的测试发现,Hog+SVM是速度和效果综合平衡性能较好的一种行人检测方法。后来,虽然很多研究人员也提出了很多改进的行人检测算法,但基本都以该算法为基础框架。因此,Hog+SVM也成为一个里程表式的算法被写入到OpenCV中。在OpenCV2.0之后的版本,都有Hog特征描述算子的API,而至于SVM,早在OpenCV1.0版本就已经集成进去了;OpenCV虽然提供了Hog和SVM的API,也提供了行人检测的sample,遗憾的是,OpenCV并没有提供样本训练的sample。这也就意味着,很多人只能用OpenCV自带的已经训练好的分类器来进行行人检测。然而,OpenCV自带的分类器是利用Navneet Dalal和Bill Triggs提供的样本进行训练的,不见得能适用于你的应用场合。因此,针对你的特定应用场景,很有必要进行重新训练得到适合你的分类器。
-----------------------------------------------------------------------------
重新训练行人检测的流程:
(1)准备训练样本集合;包括正样本集和负样本集;根据机器学习的基础知识我们知道,要利用机器学习算法进行样本训练,从而得到一个性能优良的分类器,训练样本应该是无限多的,而且训练样本应该覆盖实际应用过程中可能发生的各种情况。(很多朋友,用10来个正样本,10来个负样本进行训练,之后,就进行测试,发现效果没有想象中的那么好,就开始发牢骚,抱怨。。。对于这些人,我只能抱歉的说,对于机器学习、模式识别的认识,你还处于没有入门的阶段);实际应用过程中,训练样本不可能无限多,但无论如何,三五千个正样本,三五千个负样本,应该不是什么难事吧?(如果连这个都做不到,建议你别搞机器学习,模式识别了;训练素材都没有,怎么让机器学习到足够的信息呢?)
(2)收集到足够的训练样本之后,你需要手动裁剪样本。例如,你想用Hog+SVM来对商业步行街的监控画面中进行行人检测,那么,你就应该用收集到的训练样本集合,手动裁剪画面中的行人(可以写个简单程序,只需要鼠标框选一下,就将框选区域保存下来)。
(3)裁剪得到训练样本之后,将所有正样本放在一个文件夹中;将所有负样本放在另一个文件夹中;并将所有训练样本缩放到同样的尺寸大小。OpenCV自带的例子在训练时,就是将样本缩放为64*128进行训练的;
(4)提取所有正样本的Hog特征;
(5)提取所有负样本的Hog特征;
(6)对所有正负样本赋予样本标签;例如,所有正样本标记为1,所有负样本标记为0;
(7)将正负样本的Hog特征,正负样本的标签,都输入到SVM中进行训练;Dalal在论文中考虑到速度问题,建议采用线性SVM进行训练。这里,不妨也采用线性SVM;
(8)SVM训练之后,将结果保存为文本文件。
(9)线性SVM进行训练之后得到的文本文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个列向量。之后,再该列向量的最后添加一个元素rho。如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),就可以利用你的训练样本训练出来的分类器进行行人检测了。
OpenCV3.0相比2.X,接口更加清晰,还是有很大的改动的。
主要有几个需要注意的地方:
1. sampleLabelMat的数据类型必须为有符号整数型。
2. 加载已经训练好的分类器,需要注意:
svm = SVM::load<SVM>("SVM_HOG.xml"); //或者svm = Statmodel::load<SVM>("SVM_HOG.xml"); 在3.0里,SVM::load 是一个static function
// svm->load<SVM>("SVM_HOG.xml"); 这样使用不行
3. 一些新的接口:
Mat svecsmat = svm ->getSupportVectors();//svecsmat元素的数据类型为float
int svdim = svm ->getVarCount();//特征向量位数
4. getDecisionFunction()
Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);//alphamat和svindex必须初始化,否则getDecisionFunction()函数会报错
Mat svindex = Mat::zeros(1, numofsv,CV_64F);
Mat Result;
double rho = svm ->getDecisionFunction(0, alphamat, svindex);
5.alphamat.convertTo(alphamat, CV_32F);//将alphamat元素的数据类型重新转成CV_32F,经过getDecisionFunction后alphamat的数据类型会发生改变,为了后续的矩阵乘法,这里要修改其元素的数据类型
6. 还有一个问题,为什么Result = -1 * alphamat * svecsmat;要乘以-1????
因为机器学习的svm线性公式为y=wx+b。lphamat * svecsmat=-w,所以Result = -(-w)
本人直接使用训练好的svm_hog.xml让svm机学习,再直接读入图片让svm机来判断图片中的行人
我用的是opencv3.0 还有vs2012
在debug下生成exe,打开debug文件,其中person这类图片是待测图片,svm_hog.xml这个文件是训练好的库。这些都放到debug中,再点击exe,运行生成HOGDetectorForOpenCV.txt这是样本提取出来的特征,imgProcess.Jpg是生成的判断图片,但是误差还是很大
【源码如下】
#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;
using namespace cv::ml;
#define PosSamNO 2400 //original
positive num 正样本个数
#define NegSamNO 2400 //
original negative num 负样本个数
#define HardExampleNO 3600 //
hard negative num 难样本个数
#define AugPosSamNO 2400 //Aug
positive num 超正样本个数
#define TRAIN false
#define CENTRAL_CROP true
int main()
{
//检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9
//winsize(64,128),blocksize(16,16),blockstep(8,8),cellsize(8,8),bins9
HOGDescriptor hog(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);
int DescriptorDim;//即HOG描述子的维数。
由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
Ptr<SVM> svm = SVM::create();
if(TRAIN)
{
string ImgName;
ifstream finPos("DATA/INRIAPerson96X160PosList.txt");
ifstream finNeg("DATA/NoPersonFromINRIAList.txt");
/* #include <fstream> c++特有输入输出
ofstream //文件写操作 内存写入存储设备
ifstream //文件读操作,存储设备读区到内存中
fstream //读写操作,对打开的文件可进行读写操作 */
if (!finPos || !finNeg)
{
cout << "Pos/Neg
imglist reading failed..." << endl;
return 1;
}
Mat sampleFeatureMat;
Mat sampleLabelMat;
//loading original positive examples...
for(int num=0; num < PosSamNO && getline(finPos,ImgName); num++)
{
cout <<"Now
processing original positive image: " << ImgName << endl;
ImgName = "DataSet/INRIAPerson/train_64x128_H96/pos/" + ImgName;
Mat src = imread(ImgName);
if(CENTRAL_CROP)
src = src(Rect(16,16,64,128));
vector<float> descriptors;
hog.compute(src, descriptors, Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)
if( 0 == num )
{
DescriptorDim = descriptors.size();
sampleFeatureMat = Mat::zeros(PosSamNO +AugPosSamNO +NegSamNO +HardExampleNO, DescriptorDim, CV_32FC1);
sampleLabelMat = Mat::zeros(PosSamNO +AugPosSamNO +NegSamNO +HardExampleNO, 1, CV_32SC1);//sampleLabelMat的数据类型必须为有符号整数型
}
//将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num,i) = descriptors[i];
sampleLabelMat.at<int>(num,0) = 1;
}
finPos.close();
//positive examples augmenting...
if (AugPosSamNO > 0)
{
ifstream finAug("DATA/AugPosImgList.txt");
if (!finAug)
{
cout << "Aug
positive imglist reading failed..." << endl;
return 1;
}
for (int num = 0; num < AugPosSamNO && getline(finAug, ImgName); ++num)
{
cout << "Now
processing Aug positive image: " << ImgName << endl;
ImgName = "DATA/INRIAPerson/AugPos/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src, descriptors, Size(8,8));
for (int i = 0; i < DescriptorDim; ++i)
sampleFeatureMat.at<float>(num +PosSamNO, i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO, 0) = 1;
}
finAug.close();
}
//loading original negative examples...
for(int num = 0; num < NegSamNO && getline(finNeg,ImgName); num++)
{
cout<<"Now processing original negative image: "<<ImgName<<endl;
ImgName = "DATA/INRIAPerson/Neg/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src,descriptors,Size(8,8));
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num+PosSamNO,i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO +AugPosSamNO, 0) = -1;
}
finNeg.close();
//loading hard examples...
if(HardExampleNO > 0)
{
ifstream finHardExample("DATA/INRIAPersonHardNegList.txt");
if (!finHardExample)
{
cout << "HardExample
list reading failed..." << endl;
return 1;
}
for(int num=0; num < HardExampleNO && getline(finHardExample, ImgName); num++)
{
cout<<"Now processing hard negative image: "<<ImgName<<endl;
ImgName = "DATA/INRIAPerson/HardNeg/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src,descriptors,Size(8,8));
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num+PosSamNO+NegSamNO,i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO +AugPosSamNO +NegSamNO, 0) = -1;
}
finHardExample.close();
}
svm ->setType(SVM::C_SVC);
svm ->setC(0.01);
svm ->setKernel(SVM::LINEAR);
svm ->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 3000, 1e-6));
cout<<"Starting training..."<<endl;
svm ->train(sampleFeatureMat, ROW_SAMPLE, sampleLabelMat);
cout<<"Finishing training..."<<endl;
svm ->save("SVM_HOG.xml");
}
else {
svm = SVM::load<SVM>("SVM_HOG.xml"); //或者svm
= Statmodel::load<SVM>("SVM_HOG.xml"); static function
// svm->load<SVM>("SVM_HOG.xml"); 这样使用不行
}
Mat svecsmat = svm ->getSupportVectors();//svecsmat元素的数据类型为float
int svdim = svm ->getVarCount();//特征向量位数
int numofsv = svecsmat.rows;
Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);//alphamat和svindex必须初始化,否则getDecisionFunction()函数会报错
Mat svindex = Mat::zeros(1, numofsv,CV_64F);
Mat Result;
double rho = svm ->getDecisionFunction(0, alphamat, svindex);
alphamat.convertTo(alphamat, CV_32F);//将alphamat元素的数据类型重新转成CV_32F
Result = -1 * alphamat * svecsmat;//float
vector<float> vec;
for (int i = 0; i < svdim; ++i)
{
vec.push_back(Result.at<float>(0, i));
}
vec.push_back(rho);
//saving HOGDetectorForOpenCV.txt
ofstream fout("HOGDetectorForOpenCV.txt");
for (int i = 0; i < vec.size(); ++i)
{
fout << vec[i] << endl;
}
/*********************************Testing**************************************************/
HOGDescriptor hog_test;
hog_test.setSVMDetector(vec);
Mat src = imread("person.png");
vector<Rect> found, found_filtered;
hog_test.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);
cout<<"found.size : "<<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();
return 0;
}
那个我是天津理工大学的一名本科学生,2019届。有幸在大一考完C语言之后呢,碰到了学院的一位老师,他是做计算机视觉的,然后经过很久的积累,开始走上了简单的计算机视觉之路,就是opencv。说这么多就是让大家知道,opencv不难,难的是坚持,为自己的目标所坚持。
简单的看完毛星云的opencv3.0(那个3.0和2.0确实很多不一样,有时为了看csdn博客的以前的人做的好东西得不断得改为别人对应的版本。)学到最后简单的opencv知识是不够的,所以得了解机器学习有关得知识,从而使opencv更加智能
书籍推荐李航老师的“统计学习法”偏向数学证明为主,需要高数,线代,还有概率论的知识,可以看到不会时再从头找书看看相关的,例如什么是范数,什么是正定矩阵。。。
周志华老师的西瓜书“机器学习”偏形象,但是有时候却难理解
好了,回到主题是快速了解hog和svm
先了解svm支持向量机
建议点击看看http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms
线性的话,就是找出一条线将样本分为正样本和负样本,公式为y=wx+b,y的结果只为1或-1(1为正样本,-1为负样本)其中w,x是矩阵,也是向量,所以wx是向量的内积。
------------------------------------------------------------------------------------------------------------------
下面了解hog特征
建议点击看看http://blog.csdn.net/liulina603/article/details/8291093
总结:hog就是图片的一种特征,刚好很适合做人体检测而已
在2005年CVPR上,来自法国的研究人员Navneet Dalal 和Bill Triggs提出利用Hog进行特征提取,利用线性SVM作为分类器,从而实现行人检测。而这两位也通过大量的测试发现,Hog+SVM是速度和效果综合平衡性能较好的一种行人检测方法。后来,虽然很多研究人员也提出了很多改进的行人检测算法,但基本都以该算法为基础框架。因此,Hog+SVM也成为一个里程表式的算法被写入到OpenCV中。在OpenCV2.0之后的版本,都有Hog特征描述算子的API,而至于SVM,早在OpenCV1.0版本就已经集成进去了;OpenCV虽然提供了Hog和SVM的API,也提供了行人检测的sample,遗憾的是,OpenCV并没有提供样本训练的sample。这也就意味着,很多人只能用OpenCV自带的已经训练好的分类器来进行行人检测。然而,OpenCV自带的分类器是利用Navneet Dalal和Bill Triggs提供的样本进行训练的,不见得能适用于你的应用场合。因此,针对你的特定应用场景,很有必要进行重新训练得到适合你的分类器。
-----------------------------------------------------------------------------
重新训练行人检测的流程:
(1)准备训练样本集合;包括正样本集和负样本集;根据机器学习的基础知识我们知道,要利用机器学习算法进行样本训练,从而得到一个性能优良的分类器,训练样本应该是无限多的,而且训练样本应该覆盖实际应用过程中可能发生的各种情况。(很多朋友,用10来个正样本,10来个负样本进行训练,之后,就进行测试,发现效果没有想象中的那么好,就开始发牢骚,抱怨。。。对于这些人,我只能抱歉的说,对于机器学习、模式识别的认识,你还处于没有入门的阶段);实际应用过程中,训练样本不可能无限多,但无论如何,三五千个正样本,三五千个负样本,应该不是什么难事吧?(如果连这个都做不到,建议你别搞机器学习,模式识别了;训练素材都没有,怎么让机器学习到足够的信息呢?)
(2)收集到足够的训练样本之后,你需要手动裁剪样本。例如,你想用Hog+SVM来对商业步行街的监控画面中进行行人检测,那么,你就应该用收集到的训练样本集合,手动裁剪画面中的行人(可以写个简单程序,只需要鼠标框选一下,就将框选区域保存下来)。
(3)裁剪得到训练样本之后,将所有正样本放在一个文件夹中;将所有负样本放在另一个文件夹中;并将所有训练样本缩放到同样的尺寸大小。OpenCV自带的例子在训练时,就是将样本缩放为64*128进行训练的;
(4)提取所有正样本的Hog特征;
(5)提取所有负样本的Hog特征;
(6)对所有正负样本赋予样本标签;例如,所有正样本标记为1,所有负样本标记为0;
(7)将正负样本的Hog特征,正负样本的标签,都输入到SVM中进行训练;Dalal在论文中考虑到速度问题,建议采用线性SVM进行训练。这里,不妨也采用线性SVM;
(8)SVM训练之后,将结果保存为文本文件。
(9)线性SVM进行训练之后得到的文本文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个列向量。之后,再该列向量的最后添加一个元素rho。如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),就可以利用你的训练样本训练出来的分类器进行行人检测了。
OpenCV3.0相比2.X,接口更加清晰,还是有很大的改动的。
主要有几个需要注意的地方:
1. sampleLabelMat的数据类型必须为有符号整数型。
2. 加载已经训练好的分类器,需要注意:
svm = SVM::load<SVM>("SVM_HOG.xml"); //或者svm = Statmodel::load<SVM>("SVM_HOG.xml"); 在3.0里,SVM::load 是一个static function
// svm->load<SVM>("SVM_HOG.xml"); 这样使用不行
3. 一些新的接口:
Mat svecsmat = svm ->getSupportVectors();//svecsmat元素的数据类型为float
int svdim = svm ->getVarCount();//特征向量位数
4. getDecisionFunction()
Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);//alphamat和svindex必须初始化,否则getDecisionFunction()函数会报错
Mat svindex = Mat::zeros(1, numofsv,CV_64F);
Mat Result;
double rho = svm ->getDecisionFunction(0, alphamat, svindex);
5.alphamat.convertTo(alphamat, CV_32F);//将alphamat元素的数据类型重新转成CV_32F,经过getDecisionFunction后alphamat的数据类型会发生改变,为了后续的矩阵乘法,这里要修改其元素的数据类型
6. 还有一个问题,为什么Result = -1 * alphamat * svecsmat;要乘以-1????
因为机器学习的svm线性公式为y=wx+b。lphamat * svecsmat=-w,所以Result = -(-w)
本人直接使用训练好的svm_hog.xml让svm机学习,再直接读入图片让svm机来判断图片中的行人
我用的是opencv3.0 还有vs2012
在debug下生成exe,打开debug文件,其中person这类图片是待测图片,svm_hog.xml这个文件是训练好的库。这些都放到debug中,再点击exe,运行生成HOGDetectorForOpenCV.txt这是样本提取出来的特征,imgProcess.Jpg是生成的判断图片,但是误差还是很大
【源码如下】
#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;
using namespace cv::ml;
#define PosSamNO 2400 //original
positive num 正样本个数
#define NegSamNO 2400 //
original negative num 负样本个数
#define HardExampleNO 3600 //
hard negative num 难样本个数
#define AugPosSamNO 2400 //Aug
positive num 超正样本个数
#define TRAIN false
#define CENTRAL_CROP true
int main()
{
//检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9
//winsize(64,128),blocksize(16,16),blockstep(8,8),cellsize(8,8),bins9
HOGDescriptor hog(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);
int DescriptorDim;//即HOG描述子的维数。
由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
Ptr<SVM> svm = SVM::create();
if(TRAIN)
{
string ImgName;
ifstream finPos("DATA/INRIAPerson96X160PosList.txt");
ifstream finNeg("DATA/NoPersonFromINRIAList.txt");
/* #include <fstream> c++特有输入输出
ofstream //文件写操作 内存写入存储设备
ifstream //文件读操作,存储设备读区到内存中
fstream //读写操作,对打开的文件可进行读写操作 */
if (!finPos || !finNeg)
{
cout << "Pos/Neg
imglist reading failed..." << endl;
return 1;
}
Mat sampleFeatureMat;
Mat sampleLabelMat;
//loading original positive examples...
for(int num=0; num < PosSamNO && getline(finPos,ImgName); num++)
{
cout <<"Now
processing original positive image: " << ImgName << endl;
ImgName = "DataSet/INRIAPerson/train_64x128_H96/pos/" + ImgName;
Mat src = imread(ImgName);
if(CENTRAL_CROP)
src = src(Rect(16,16,64,128));
vector<float> descriptors;
hog.compute(src, descriptors, Size(8,8));//计算HOG描述子,检测窗口移动步长(8,8)
if( 0 == num )
{
DescriptorDim = descriptors.size();
sampleFeatureMat = Mat::zeros(PosSamNO +AugPosSamNO +NegSamNO +HardExampleNO, DescriptorDim, CV_32FC1);
sampleLabelMat = Mat::zeros(PosSamNO +AugPosSamNO +NegSamNO +HardExampleNO, 1, CV_32SC1);//sampleLabelMat的数据类型必须为有符号整数型
}
//将计算好的HOG描述子复制到样本特征矩阵sampleFeatureMat
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num,i) = descriptors[i];
sampleLabelMat.at<int>(num,0) = 1;
}
finPos.close();
//positive examples augmenting...
if (AugPosSamNO > 0)
{
ifstream finAug("DATA/AugPosImgList.txt");
if (!finAug)
{
cout << "Aug
positive imglist reading failed..." << endl;
return 1;
}
for (int num = 0; num < AugPosSamNO && getline(finAug, ImgName); ++num)
{
cout << "Now
processing Aug positive image: " << ImgName << endl;
ImgName = "DATA/INRIAPerson/AugPos/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src, descriptors, Size(8,8));
for (int i = 0; i < DescriptorDim; ++i)
sampleFeatureMat.at<float>(num +PosSamNO, i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO, 0) = 1;
}
finAug.close();
}
//loading original negative examples...
for(int num = 0; num < NegSamNO && getline(finNeg,ImgName); num++)
{
cout<<"Now processing original negative image: "<<ImgName<<endl;
ImgName = "DATA/INRIAPerson/Neg/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src,descriptors,Size(8,8));
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num+PosSamNO,i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO +AugPosSamNO, 0) = -1;
}
finNeg.close();
//loading hard examples...
if(HardExampleNO > 0)
{
ifstream finHardExample("DATA/INRIAPersonHardNegList.txt");
if (!finHardExample)
{
cout << "HardExample
list reading failed..." << endl;
return 1;
}
for(int num=0; num < HardExampleNO && getline(finHardExample, ImgName); num++)
{
cout<<"Now processing hard negative image: "<<ImgName<<endl;
ImgName = "DATA/INRIAPerson/HardNeg/" + ImgName;
Mat src = imread(ImgName);
vector<float> descriptors;
hog.compute(src,descriptors,Size(8,8));
for(int i=0; i<DescriptorDim; i++)
sampleFeatureMat.at<float>(num+PosSamNO+NegSamNO,i) = descriptors[i];
sampleLabelMat.at<int>(num +PosSamNO +AugPosSamNO +NegSamNO, 0) = -1;
}
finHardExample.close();
}
svm ->setType(SVM::C_SVC);
svm ->setC(0.01);
svm ->setKernel(SVM::LINEAR);
svm ->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 3000, 1e-6));
cout<<"Starting training..."<<endl;
svm ->train(sampleFeatureMat, ROW_SAMPLE, sampleLabelMat);
cout<<"Finishing training..."<<endl;
svm ->save("SVM_HOG.xml");
}
else {
svm = SVM::load<SVM>("SVM_HOG.xml"); //或者svm
= Statmodel::load<SVM>("SVM_HOG.xml"); static function
// svm->load<SVM>("SVM_HOG.xml"); 这样使用不行
}
Mat svecsmat = svm ->getSupportVectors();//svecsmat元素的数据类型为float
int svdim = svm ->getVarCount();//特征向量位数
int numofsv = svecsmat.rows;
Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);//alphamat和svindex必须初始化,否则getDecisionFunction()函数会报错
Mat svindex = Mat::zeros(1, numofsv,CV_64F);
Mat Result;
double rho = svm ->getDecisionFunction(0, alphamat, svindex);
alphamat.convertTo(alphamat, CV_32F);//将alphamat元素的数据类型重新转成CV_32F
Result = -1 * alphamat * svecsmat;//float
vector<float> vec;
for (int i = 0; i < svdim; ++i)
{
vec.push_back(Result.at<float>(0, i));
}
vec.push_back(rho);
//saving HOGDetectorForOpenCV.txt
ofstream fout("HOGDetectorForOpenCV.txt");
for (int i = 0; i < vec.size(); ++i)
{
fout << vec[i] << endl;
}
/*********************************Testing**************************************************/
HOGDescriptor hog_test;
hog_test.setSVMDetector(vec);
Mat src = imread("person.png");
vector<Rect> found, found_filtered;
hog_test.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);
cout<<"found.size : "<<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();
return 0;
}
相关文章推荐
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 运用HOG特征与SVM检测行人
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器,进行HOG行人检测。
- 自己训练SVM分类器进行HOG行人检测
- 自己训练SVM分类器进行HOG行人检测
- 自己训练的Hog+Svm 行人检测
- 自己训练SVM分类器进行HOG行人检测
- HOG+SVM行人检测博客资料汇总
- Hog特征和SVM进行行人检测
- 基于HOG的简单行人检测计数
- Opencv中HOG+SVM进行行人检测
- HOG+SVM行人检测识别的两种方法
- HOG+SVM行人检测--OpenCV源码不完全解释