如何使用SVM从视频中检测对象

时间:2013-08-11 13:22:56

标签: c++ opencv image-processing computer-vision

这是我训练例如车辆数据集的代码,当它完全训练时,我希望它从视频(.avi)预测数据(车辆),how to predict trained data from video and how to add that part in it ?,我想要当车辆在视频中显示它被视为1并且cout表示检测到物体,如果第二辆车到达它则将计数增加为2

    IplImage *img2;
    cout<<"Vector quantization..."<<endl;
    collectclasscentroids();
    vector<Mat> descriptors = bowTrainer.getDescriptors();
    int count=0;
    for(vector<Mat>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
    {
       count += iter->rows;
    }
    cout<<"Clustering "<<count<<" features"<<endl;
    //choosing cluster's centroids as dictionary's words
    Mat dictionary = bowTrainer.cluster();
    bowDE.setVocabulary(dictionary);
    cout<<"extracting histograms in the form of BOW for each image "<<endl;
    Mat labels(0, 1, CV_32FC1);
    Mat trainingData(0, dictionarySize, CV_32FC1);
    int k = 0;
    vector<KeyPoint> keypoint1;
    Mat bowDescriptor1;
    //extracting histogram in the form of bow for each image 
   for(j = 1; j <= 4; j++)
    for(i = 1; i <= 60; i++)
            {
              sprintf( ch,"%s%d%s%d%s","train/",j," (",i,").jpg");
              const char* imageName = ch;
              img2 = cvLoadImage(imageName, 0); 
              detector.detect(img2, keypoint1);
              bowDE.compute(img2, keypoint1, bowDescriptor1);
              trainingData.push_back(bowDescriptor1);
              labels.push_back((float) j);
             }
    //Setting up SVM parameters
    CvSVMParams params;
    params.kernel_type = CvSVM::RBF;
    params.svm_type = CvSVM::C_SVC;
    params.gamma = 0.50625000000000009;
    params.C = 312.50000000000000;
    params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 0.000001);
    CvSVM svm;



    printf("%s\n", "Training SVM classifier");

    bool res = svm.train(trainingData, labels, cv::Mat(), cv::Mat(), params);

    cout<<"Processing evaluation data..."<<endl;


    Mat groundTruth(0, 1, CV_32FC1);
    Mat evalData(0, dictionarySize, CV_32FC1);
    k = 0;
    vector<KeyPoint> keypoint2;
    Mat bowDescriptor2;


    Mat results(0, 1, CV_32FC1);;
    for(j = 1; j <= 4; j++)
      for(i = 1; i <= 60; i++)
         {
           sprintf( ch, "%s%d%s%d%s", "eval/", j, " (",i,").jpg");
           const char* imageName = ch;
           img2 = cvLoadImage(imageName,0);
           detector.detect(img2, keypoint2);
           bowDE.compute(img2, keypoint2, bowDescriptor2);
           evalData.push_back(bowDescriptor2);
           groundTruth.push_back((float) j);
           float response = svm.predict(bowDescriptor2);
           results.push_back(response);
         }



    //calculate the number of unmatched classes 
    double errorRate = (double) countNonZero(groundTruth- results) / evalData.rows;

The question is此代码不是从视频中预测的,我想知道如何从视频中预测它,就像我想要从电影中检测到车辆一样,就像它应该在找到车辆时显示1电影

对于那些不理解这个问题的人:

我想在上面的代码中播放电影

VideoCapture cap("movie.avi"); //movie.avi is with deleted background

假设我有一个包含车辆的训练数据,而且“movie.avi”包含5辆车,所以它应该从movie.avi中检测到这些车辆并给我5作为输出

如何在上面的代码中执行此部分

4 个答案:

答案 0 :(得分:2)

从查看代码设置

params.svm_type = CvSVM::C_SVC;

您似乎用两个以上的课程训练您的分类器。交通场景中的一个典型例子可能是汽车/行人/自行车/ ......但是,您只是想要一种方法来检测汽车。如果没有您的训练数据和视频的描述,很难说,如果您的想法有意义。我想以前的答案假设如下:

您遍历每个帧并想要输出该帧中的汽车数量。因此,一个框架可能包含多个汽车,比如说5.如果你将整个框架作为分类器的输入,它可能会响应“汽车”,即使设置可能稍微偏离概念。使用这种方法无法可靠地检索汽车数量。

相反,建议是尝试滑动窗口方法。这意味着,例如,您循环遍历帧的每个像素,并将像素周围的区域(称为子窗口感兴趣区域)作为输入分类器。假设一个固定的比例,子窗口的大小可以是150x50px,也可以是你的训练数据。您可以在训练数据中固定汽车的比例,但在真实世界的视频中,汽车将具有不同的尺寸。为了找到不同规模的汽车,假设它的数量是训练数据的两倍,典型的方法是缩放图像(例如用2倍)并重复滑动窗口方法。 p>

通过对所有相关比例重复此操作,您最终会得到一个算法,该算法为您提供每个像素位置,并为每个比例缩放结果。这意味着您有三个循环,换句话说,有三个维度(图像宽度,图像高度,比例)。这最好被理解为三维金字塔。 “为什么是金字塔?”你可能会问。因为每次缩放图像(例如2)时图像变小(/更大),下一个刻度是不同大小的图像(例如,大小的一半)。

像素位置表示汽车的位置,刻度表示尺寸。现在,如果你有一个N级分类器,这个金字塔中的每个插槽都将包含一个表示该类的数字(1,...,N)。如果你有一个二元分类器(汽车/没有汽车),那么你最终会得到每个包含0或1的插槽。即使在这个简单的情况下,你也很想简单地计算1的数量并将计数输出为汽车数量,你仍然有一个问题,即同一辆车可能有多个响应。因此,如果你有一个汽车探测器可以提供0到1之间的连续响应,然后你可以在这个金字塔中找到最大值,那就更好了。每个最大值表示一辆车。这种检测成功地与角落特征一起使用,您可以在所谓的尺度空间金字塔中检测感兴趣的角落

总结一下,无论你是将问题简化为二元分类问题(“汽车”/“没有汽车”),还是你正在坚持区分多个类别(“汽车”/)的更困难的任务“动物”/“行人”/ ...),你仍然有每个框架中的尺度和位置问题需要解决。

答案 1 :(得分:0)

使用图像的代码是使用OpenCV的C接口编写的,因此可能很容易使用它而不是使用C ++视频接口。

在这种情况下,沿着这些方向的东西应该起作用:

CvCapture *capture = cvCaptureFromFile("movie.avi");

IplImage *img = 0;
while(img = cvQueryFrame(capture))
{
       // Process image
       ...
}

答案 2 :(得分:0)

您应该实现滑动窗口方法。在每个窗口中,您应该应用SVM来获取候选人。然后,一旦你为整个图像完成了它,你应该合并候选者(如果你检测到一个对象,那么很可能你会在几个像素的移位中再次检测到它 - 这就是候选者的意思)

查看openCV上的V&amp; J代码或latentSVM代码(按部分检测),看看它是如何在那里完成的。

顺便说一下,我会使用LatentSVM代码(按部件检测)来检测车辆。它训练了汽车和公共汽车的模型。

祝你好运。

答案 3 :(得分:0)

你需要探测器,而不是分类器。看看之前提到的Haar级联,LBP级联,latentSVM或HOG探测器。

我会解释原因。检测器通常通过滑动窗口逐行扫描图像。在几个尺度。在每个窗口检测器中解决问题:“对象/非对象”。它可能会给你粗略的结果,但速度非常快。诸如BOW之类的分类器对于此任务的工作非常缓慢。然后,您应该将分类器应用于检测器找到的区域。