SVM训练(C++实现)

在很多文献中,都把HOG和SVM结合起来使用,可以得到很不错的分类效果,SVM就不用再复习啦,就是一个线性分类器,给一个简单的图就能很好理解,

对于有标签的正样本和负样本,如果只有两个维度,也就是只有两个特征,要做的就是找到一条线,能够很好的划分为两个区域分别包含正负样本,并且这条线尽可能远离两个样本中心
SVM训练(C++实现)
(摘自上课的PPT)

但是这是针对二维的情况,如果扩展到多维,可能就无法找到一条线,即使找到了也可能有很多样本发生了错分,所以就需要在更高维度上考虑,高斯是最常用的。

目前我是打算将23维图像降为1维,空间信息损失实在太多啦,但是也想看看效果,就跑了跑。

一、代码及解释

	//使用SVM分类器训练  
    //设置参数的方式1
    Ptr<SVM> 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<<"//-------------开始训练-------//" <<endl;
    clock_t start, end;
    start = clock();

    //使用SVM分类器训练
    //设置参数,注意Ptr的使用
    cv::Ptr<cv::ml::SVM> 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;

    /*
    SVM训练完成后得到的XML文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;
    将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个行向量,将该向量前面乘以-1。之后,再该行向量的最后添加一个元素rho。
    如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),
    */
    //获取支持向量机:矩阵默认是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<float>(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<float>(0,i));
    }
    fprintf(fp, "%f", rho);
    fclose(fp);

    cout <<"真正参数得到啦"<< endl;

二、总结

如果要使用SVM进行训练的话,可能需要GPU,又或者是我维度太高了,想要二分类比较困难,这还是一个问题,等后面来解决!

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2022年5月30日 上午11:17
下一篇 2022年5月30日 上午11:19

相关推荐