C++ OpenCV:跟踪在街上移动的人

Áko*_*róy 10 c++ opencv tracking

我正在尝试让人们跟踪使用C++中的OpenCV进行跟踪工作,用相机看着街道,人们在移动它.我拍摄的一个示例视频,我正在使用,请看这里:http://akos.maroy.hu/~akos/eszesp/MVI_0778.MOV

我读了这个主题,我尝试了很多东西,包括:

  • 背景检测和创建轮廓
  • 尝试检测blob(blob的关键点)
  • 使用HOGDescriptor为每个帧使用人物检测器

但这些都没有提供好的结果.对于我的示例代码,请参见下文.根据上述视频输出代码,请参阅:http://akos.maroy.hu/~akos/eszesp/ize.avi.在背景中检测到的轮廓为红色,轮廓的边界矩形为绿色,HOG人检测器结果为蓝色.

我遇到的具体问题是:

背景检测,然后找到轮廓似乎工作正常,虽然有一些误报.但主要的缺点是,很多时候一个人被"切割"成多个轮廓.是否有一种简单的方法可以将这些"加入"在一起,可能是假定的"理想"人物大小或其他方式?

对于HOG人物检测器,在我的情况下,它很少识别图像上的真实人物.那我可能做错了什么?

所有指针,想法欢迎!

因此,到目前为止,我正在使用的代码,这是我在这里和那里找到的各种样本的代理和荣耀:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>

int main(int argc, char *argv[])
{
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " in.file out.file" << std::endl;
        return -1;
    }

    cv::Mat frame;
    cv::Mat back;
    cv::Mat fore;
    std::cerr << "opening " << argv[1] << std::endl;
    cv::VideoCapture cap(argv[1]);
    cv::BackgroundSubtractorMOG2 bg;
    //bg.nmixtures = 3;
    //bg.bShadowDetection = false;

    cv::VideoWriter output;
    //int ex = static_cast<int>(cap.get(CV_CAP_PROP_FOURCC));
    int ex = CV_FOURCC('P','I','M','1');
    cv::Size size = cv::Size((int) cap.get(CV_CAP_PROP_FRAME_WIDTH),
                             (int) cap.get(CV_CAP_PROP_FRAME_HEIGHT));
    std::cerr << "saving to " << argv[2] << std::endl;
    output.open(argv[2], ex, cap.get(CV_CAP_PROP_FPS), size, true);

    std::vector<std::vector<cv::Point> > contours;

    cv::namedWindow("Frame");
    cv::namedWindow("Fore");
    cv::namedWindow("Background");


    cv::SimpleBlobDetector::Params params;
    params.minThreshold = 40;
    params.maxThreshold = 60;
    params.thresholdStep = 5;
    params.minArea = 100; 
    params.minConvexity = 0.3;
    params.minInertiaRatio = 0.01;
    params.maxArea = 8000;
    params.maxConvexity = 10;
    params.filterByColor = false;
    params.filterByCircularity = false;


    cv::SimpleBlobDetector blobDtor(params);
    blobDtor.create("SimpleBlob");

    std::vector<std::vector<cv::Point> >    blobContours;
    std::vector<cv::KeyPoint>               keyPoints;
    cv::Mat                                 out;

    cv::HOGDescriptor hog;
    hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());


    for(;;)
    {
        cap >> frame;

        bg.operator ()(frame, fore);

        bg.getBackgroundImage(back);
        cv::erode(fore, fore, cv::Mat());
        cv::dilate(fore, fore, cv::Mat());

        blobDtor.detect(fore, keyPoints, cv::Mat());

        //cv::imshow("Fore", fore);

        cv::findContours(fore, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
        cv::drawContours(frame, contours, -1, cv::Scalar(0,0,255), 2);

        std::vector<std::vector<cv::Point> >::const_iterator it = contours.begin();
        std::vector<std::vector<cv::Point> >::const_iterator end = contours.end();
        while (it != end) {
            cv::Rect bounds = cv::boundingRect(*it);
            cv::rectangle(frame, bounds, cv::Scalar(0,255,0), 2);

            ++it;
        }

        cv::drawKeypoints(fore, keyPoints, out, CV_RGB(0,255,0), cv::DrawMatchesFlags::DEFAULT);
        cv::imshow("Fore", out);


        std::vector<cv::Rect> found, found_filtered;
        hog.detectMultiScale(frame, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
        for (int i = 0; i < found.size(); ++i) {
            cv::Rect r = found[i];
            int j = 0;
            for (; j < found.size(); ++j) {
                if (j != i && (r & found[j]) == r) {
                    break;
                }
            }
            if (j == found.size()) {
                found_filtered.push_back(r);
            }
        }

        for (int i = 0; i < found_filtered.size(); ++i) {
            cv::Rect r = found_filtered[i];
            cv::rectangle(frame, r.tl(), r.br(), cv::Scalar(255,0,0), 3);
        }


        output << frame;

        cv::resize(frame, frame, cv::Size(1280, 720));
        cv::imshow("Frame", frame);

        cv::resize(back, back, cv::Size(1280, 720));
        cv::imshow("Background", back);



        if(cv::waitKey(30) >= 0) break;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

nki*_*int 10

实际上,这是一个非常广泛的话题.有很多科学论文试图解决这个问题.你应该先读一些东西.

简而言之:背景检测和轮廓是最简单的技术.OpenCV具有非常好的实现,也针对gpu进行了优化.为了优化前景/背景斑点,您可以使用一些形态学操作,尝试关闭斑点中的洞并获得更好的结果.但不要指望完美的结果.背景减法是一项困难的操作,您可以花费数小时来处理给定数据集的微调参数,然后在现实世界中尝试您的代码并且无效.灯光,阴影,背景改变与不感兴趣的对象..只是提到一些问题.

所以..不,没有一种简单而标准的技术来处理所谓的"blob碎片化"或"拆分合并"问题(有时一个人被分成更多的blob,有时候更多的人被合并在一个blob中).同样,它充满了关于这一论点的科学论文.但是有一些技术可以处理不完整或杂乱观察的跟踪.最简单的方法之一是尝试用卡尔曼滤波器进行一些不完整的观察来推断系统的真实状态.Opencv有一个很好的实现.同样,如果您对"卡尔曼滤波器跟踪"或"GNN数据关联"进行一些搜索,您会发现很多.

如果您想使用某些几何信息,例如估计人的身高等,您可以这样做,但您需要相机的校准参数.这意味着可以使用它们(标准iphone相机的微软kinect有其参数可用)或通过相机校准过程计算它们.这意味着下载棋盘图像,将其打印在纸上,然后拍摄一些图片.然后,OpenCV拥有进行校准的所有方法.之后,您需要估计地平面,然后使用一些简单的渲染项目/非项目方法从前后2d到3d坐标,并估计3d标准人的2d边界框.

利用探测器对"行人跟踪"提取观测的现代方法.背景减法可以给出一个地图,试图检测到不在孔图像上搜索,但在这种情况下,斑点检测是无用的.在OpenCV中,在这种情况下更常用的实现是Haar Adaboost检测器和HOG检测器.HOG检测器似乎在某些情况下给出了更好的结果.已经在OpenCV中实现的分类器包括用于Haar的人脸检测器和人们检测HOG.您将在OpenCV存储库中的cpp和python示例中找到示例.

如果标准检测失败(您的视频大小不同,或者您必须检测除行人之外的其他对象)..您必须训练自己的探测器.这意味着收集一些你想要检测的对象的图像(正样本),以及一些带有其他东西的图​​像(负样本),并用机器学习技术(如SVN)训练你自己的分类器.再次,谷歌是你的朋友:)

祝好运!


Dav*_*man 3

你见过读书人追踪器吗?这是一个研究项目,但是开源的并且非常有效。看这里

它现在可能还不是最先进的,但是源代码是可用的,并且结构非常好。