在很多文献中,都把HOG和SVM结合起来使用,可以得到很不错的分类效果,SVM就不用再复习啦,就是一个线性分类器,给一个简单的图就能很好理解,
对于有标签的正样本和负样本,如果只有两个维度,也就是只有两个特征,要做的就是找到一条线,能够很好的划分为两个区域分别包含正负样本,并且这条线尽可能远离两个样本中心
(摘自上课的PPT)
但是这是针对二维的情况,如果扩展到多维,可能就无法找到一条线,即使找到了也可能有很多样本发生了错分,所以就需要在更高维度上考虑,高斯是最常用的。
目前我是打算将23维图像降为1维,空间信息损失实在太多啦,但是也想看看效果,就跑了跑。
一、代码及解释
//使用SVM分类器训练
//设置参数的方式1
Ptr svm = SVM::create();
svm->setKernel(SVM::RBF);
svm->setType(SVM::C_SVC);
svm->setC(10);
svm->setCoef0(1.0);
svm->setP(1.0);
svm->setNu(0.5);
svm->setTermCriteria(TermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON));
//使用SVM学习
//
svm->train(featureVectorOfSample, ROW_SAMPLE, classOfSample);
//保存分类器
svm->save("Classifier.xml");
cout<<"//-------------开始训练-------//" <二、总结svm = cv::ml::SVM::create(); svm->setType(cv::ml::SVM::C_SVC); svm->setKernel(cv::ml::SVM::LINEAR);//注意必须使用线性SVM进行训练,因为HogDescriptor检测函数只支持线性检测!!! svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10, FLT_EPSILON)); //迭代终止条件 //使用SVM学习 svm->train(samFeatureMat,cv::ml::ROW_SAMPLE, samLabelMat); //保存分类器(里面包括了SVM的参数,支持向量,α和rho) svm->save("Classifier.xml"); end = clock(); cout << "The obtain hog feature run time is :" << (double)(end - start) / CLOCKS_PER_SEC << "s" << endl; //获取支持向量机:矩阵默认是CV_32F Mat supportVector = svm->getSupportVectors();// //获取alpha和rho Mat alpha;//每个支持向量对应的参数α(拉格朗日乘子),默认alpha是float64的 Mat svIndex;//支持向量所在的索引 float rho = svm->getDecisionFunction(0, alpha, svIndex); //转换类型:这里一定要注意,需要转换为32的 Mat alpha2; alpha.convertTo(alpha2, CV_32FC1); //结果矩阵,两个矩阵相乘 Mat result(1, 3780, CV_32FC1); result = alpha2*supportVector; //乘以-1,这里为什么会乘以-1? //注意因为svm.predict使用的是alpha*sv*another-rho,如果为负的话则认为是正样本,在HOG的检测函数中,使用rho+alpha*sv*another(another为-1) for (int i = 0; i < 3780; ++i) result.at (0, i) *= -1; //将分类器保存到文件,便于HOG识别 //这个才是真正的判别函数的参数(ω),HOG可以直接使用该参数进行识别 FILE *fp = fopen("HOG_SVM.txt", "wb"); for (int i = 0; i<3780; i++) { fprintf(fp, "%f n", result.at (0,i)); } fprintf(fp, "%f", rho); fclose(fp); cout <<"真正参数得到啦"<< endl;
如果要使用SVM进行训练的话,可能需要GPU,又或者是我维度太高了,想要二分类比较困难,这还是一个问题,等后面来解决!



