【机器学习】HOG+SVM进行车辆检测的流程及源码

在进行机器学习检测车道线时,参考了这篇博文,基于LBP+SVM实现了车道线检测的初步效果。觉得讲解很到位,代码也容易理解和修改,故在此分享,供更多人学习。

HOG SVM 车辆检测

  近期需要对卡口车辆的车脸进行检测,首先选用一个常规的检测方法即是hog特征与SVM,Hog特征是由dalal在2005年提出的用于道路中行人检测的方法,并且取的了不错的识别效果。在人脸检测方面目前主流的方法,先不考虑复杂的深度学习,大多采用Haar和Adaboost的手段来实现。我接下来将会用着两种方法来实现对卡口的车辆检测。
  首先引出 Hog特征,Hog特征是梯度方向直方图,是一种底层的视觉特征,主要描述的是图像中的梯度分布情况,而梯度分布信息主要是集中在图像中不同内容之间的边界之处,可以较好的反应图像的基本轮廓面貌。在此处并不展开对描述子的详细介绍,给出一个我当时看的博客链接,对描述子原理分析的比较透彻。hog特征原理

接下来是整个特征提取、训练、检测的流程:
1.首先是准备训练样本,分别是正样本和负样本以及测试样本。正负样本一般来说负样本最好是正样本的2-3倍比较好,覆盖面不要是乱七八糟的图像,要贴合实际应用时的场景来选取,样本对训练过程很重要,很重要,很重要,不要以为随随便便弄一些照片就OK。
2.在程序中导入测试样本,分别提取相应的Hog特征,这个地方我有两点要说明:
  2.1.样本的尺度要正则化,也就是样本的尺寸要一样,这样可以排除训练样本尺度对模型训练的影响,在正则化的时候,尽量是不要改变其比例。
  2.2.在hog特征描述子初始化的时候,需要设置窗口大小,块大小,块滑动大小,以及细胞大小和直方图相应的bin的数目,窗口大小要和输入的训练样本的尺寸一样。

3.提取正负样本的hog特征,我在这里采用的是128×128的规模,是正方形的车脸,描述子规模是8100维。
4.SVM采用opencv中自带的,其实opencv中采用的也是某一个版本的LIBSVM,只是重新封装了接口的操作而已。
5.在SVM处,需要注意的是如果之后你要用SVM中自带的detector,也就是用setSVMDetector的话,这个检测器已经是写好了的专门用了处理线性核训练的模型,因为当时dalal用的就是Hog与线性的SVM特征,而且opencv自带的只支持线性的,如果你要用高斯特征即RBF核,不可以采用setSVMDetector,你用了就会出错,根本检测不到真实的位置,这里非常关键,你如果要做分类的话可以直接调用predict,但此处应该只是对车脸与非车脸做,而不是在一张图中找出车脸,如果你要找出目标物,需要自己写相应的detector,来应用你训练好的模型!!!
6.在检测时,检测窗口的大小必须和训练样本的尺寸是一样的,就是训练时的Hog窗口大小和检测时Hog窗口大小必须保持一致,剩下的就是检测过程中看看没有没嵌套什么的,代码如下:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;


#define TRAIN//开关控制是否训练还是直接载入训练好的模型

class MySVM: public CvSVM
{
public:
    double * get_alpha_data()
    {
        return this->decision_func->alpha;
    }
    double  get_rho_data()
    {
        return this->decision_func->rho;
    }
};

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

    MySVM SVM;
    int descriptorDim;
    
    string buffer;
    string trainImg;
    vector posSamples;
    vector negSamples;
    vector testSamples;
    int posSampleNum;
    int negSampleNum;
    int testSampleNum;
    string basePath = "";//相对路径之前加上基地址,如果训练样本中是相对地址,则都加上基地址
    double rho;

#ifdef TRAIN
        ifstream fInPos("D:\\DataSet\\CarFaceDataSet\\PositiveSample.txt");//读取正样本
        ifstream fInNeg("D:\\DataSet\\CarFaceDataSet\\NegtiveSample.txt");//读取负样本
    
        while (fInPos)//讲正样本读入imgPathList中
        {
            if(getline(fInPos, buffer))
                posSamples.push_back(basePath + buffer);
        }
        posSampleNum = posSamples.size();
        fInPos.close();

        while(fInNeg)//读取负样本
        {
            if (getline(fInNeg, buffer))
                negSamples.push_back(basePath + buffer);
        }
        negSampleNum = negSamples.size();
        fInNeg.close();

        Mat sampleFeatureMat;//样本特征向量矩阵
        Mat sampleLabelMat;//样本标签

        HOGDescriptor * hog = new HOGDescriptor (cvSize(128, 128), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);
        vector descriptor;

        for(int i = 0 ; i < posSampleNum; i++)// 处理正样本
        {
            Mat inputImg = imread(posSamples[i]);
            cout<<"processing "<compute(trainImg, descriptor, Size(8, 8));
            descriptorDim = descriptor.size();

            if(i == 0)//首次特殊处理根据检测到的维数确定特征矩阵的尺寸
            {
                sampleFeatureMat = Mat::zeros(posSampleNum + negSampleNum, descriptorDim, CV_32FC1);
                sampleLabelMat = Mat::zeros(posSampleNum + negSampleNum, 1, CV_32FC1);
            }

            for(int j = 0; j < descriptorDim; j++)//将特征向量复制到矩阵中
            {
                sampleFeatureMat.at(i, j) = descriptor[j];
            }

            sampleLabelMat.at(i, 0) = 1;
        }

        cout<<"extract posSampleFeature done"<compute(trainImg, descriptor, Size(8,8));
            descriptorDim = descriptor.size();

            for(int j = 0; j < descriptorDim; j++)//将特征向量复制到矩阵中
            {
                sampleFeatureMat.at(posSampleNum + i, j) = descriptor[j];
            }

            sampleLabelMat.at(posSampleNum + i, 0) = -1;
        }

        cout<<"extract negSampleFeature done"<(i, j)<<" ";
            }
            foutFeature<<"\n";
        }
        foutFeature.close();
        cout<<"output posSample and negSample Feature done"<(i,j) = pSupportVectorData[j];
        }
    }

    double *pAlphaData = SVM.get_alpha_data();
    for (int i = 0; i < supportVectorNum; i++)//复制函数中的alpha 记住决策公式Y= wx+b
    {
        alphaMat.at(0, i) = pAlphaData[i];
    }

    resultMat = -1 * alphaMat * supportVectorMat; //alphaMat就是权重向量

    //cout< myDetector;
    for (int i = 0 ;i < descriptorDim; i++)
    {
        myDetector.push_back(resultMat.at(0, i));
    }

    rho = SVM.get_rho_data();
    myDetector.push_back(rho);
    cout<<"检测子维数 "< found, foundFiltered;
        cout<<"MultiScale detect "<

结果如下:

【机器学习】HOG+SVM进行车辆检测的流程及源码_第1张图片
【机器学习】HOG+SVM进行车辆检测的流程及源码_第2张图片
【机器学习】HOG+SVM进行车辆检测的流程及源码_第3张图片
【机器学习】HOG+SVM进行车辆检测的流程及源码_第4张图片

总体效果还是不错的,如果对hardexample,进行进一步训练,以及样本的数据进行clean,相信精度还可以进一步提高,并且现在维数也比价高,位了加快检测还可以用PCA进一步降维,但必须自己重新写detector了哦,一定要好好理解一下detector,其实hog + svm的代码很多,本质上都是差不多的。

原地址:https://www.cnblogs.com/louyihang-loves-baiyan/p/4658478.html

你可能感兴趣的:(OpenCv,智能驾驶,机器学习,C/C++)