如何使用支持向量机从视频中检测对象

How to detect object from video using SVM

本文关键字:检测 对象 视频 何使用 支持 向量机      更新时间:2023-10-16

这是我训练数据集的代码,例如车辆,当它完全训练时,我希望它从视频(.avi)预测数据(车辆),how to predict trained data from video and how to add that part in it ?,我希望当车辆在视频中显示时,它将其计数为1,并确保检测到对象,如果第二辆车来了,它将计数增加为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("%sn", "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.awi中检测到这些车辆,并将5作为输出

如何在上面的代码中完成这一部分

从查看您的代码设置

params.svm_type = CvSVM::C_SVC;

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

循环浏览每一帧,并希望输出该帧中的汽车数量。因此,一个车架可以包含多个汽车,例如5辆。如果您将整个帧作为分类器的输入,它可能会响应"car",即使设置在概念上可能有点偏离。用这种方法无法可靠地检索汽车数量。

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

通过对所有相关的尺度重复这一点,你最终会得到一个算法,为每个像素位置和每个尺度提供分类器的结果。这意味着你有三个循环,换句话说,有三个维度(图像宽度、图像高度、比例)。这最好理解为一个三维金字塔。"为什么是金字塔?"你可能会问。因为每次缩放图像(比如2),图像都会变小(/变大),下一个缩放是不同大小的图像(例如大小的一半)。

像素位置表示汽车的位置,刻度表示汽车的大小。现在,如果你有一个N类分类器,这个金字塔中的每个槽都会包含一个数字(1,…,N)来表示类别。如果你有一个二进制分类器(car/no-car),那么你会得到每个包含0或1的槽。即使在这种简单的情况下,你会很想简单地计算1的数量,并将其输出为汽车数量,但你仍然存在同一辆汽车可能有多个响应的问题。因此,如果你有一个汽车探测器,它能给出0到1之间的连续响应,然后你可以在这个金字塔中找到最大值,那就更好了。每个最大值表示一辆车。这种检测成功地与角点特征一起使用,在所谓的比例空间金字塔中检测感兴趣的角点。

总之,无论你是将问题简化为二元分类问题("车"/"无车"),还是坚持更难的任务,即区分多个类别("车"/"动物"/"行人"/…),你仍然需要解决每个框架中的规模和位置问题。

使用图像的代码是用OpenCV的C接口编写的,所以使用它可能比使用C++视频接口更容易。

在这种情况下,沿着这些路线的某些事情应该起作用:

CvCapture *capture = cvCaptureFromFile("movie.avi");
IplImage *img = 0;
while(img = cvQueryFrame(capture))
{
       // Process image
       ...
}

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

看看V&J代码或latentSVM代码(通过部件检测),看看它是如何在那里完成的。

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

祝你好运。

您需要检测器,而不是分类器。看看前面提到的Haar级联、LBP级联、latentSVM或HOG检测器。

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