使用光流的 OpenCV 跟踪

Posted

技术标签:

【中文标题】使用光流的 OpenCV 跟踪【英文标题】:OpenCV tracking using optical flow 【发布时间】:2012-03-30 20:55:15 【问题描述】:

我使用它作为我的跟踪算法的基础。

    //1. detect the features
    cv::goodFeaturesToTrack(gray_prev, // the image 
    features,   // the output detected features
    max_count,  // the maximum number of features 
    qlevel,     // quality level
    minDist);   // min distance between two features

    // 2. track features
    cv::calcOpticalFlowPyrLK(
    gray_prev, gray, // 2 consecutive images
    points_prev, // input point positions in first im
    points_cur, // output point positions in the 2nd
    status,    // tracking success
    err);      // tracking error

cv::calcOpticalFlowPyrLK 将前一张图像中的点向量作为输入,并在下一张图像上返回适当的点。假设我在上一张图像上有随机像素 (x, y),如何使用 OpenCV 光流函数计算该像素在下一张图像上的位置?

【问题讨论】:

【参考方案1】:

在您编写时,cv::goodFeaturesToTrack 将图像作为输入并生成它认为“易于跟踪”的点向量。这些是根据它们从周围环境中脱颖而出的能力来选择的,并且是基于图像中的哈里斯角。跟踪器通常会通过将第一张图像传递给 goodFeaturesToTrack 并获得一组要跟踪的特征来初始化。然后这些特征可以作为前面的点传递给cv::calcOpticalFlowPyrLK,连同序列中的下一个图像,它将产生下一个点作为输出,然后在下一次迭代中成为输入点。

如果您想尝试跟踪一组不同的像素(而不是由cv::goodFeaturesToTrack 或类似函数生成的特征),只需将这些与下一张图像一起提供给cv::calcOpticalFlowPyrLK

很简单,在代码中:

// Obtain first image and set up two feature vectors
cv::Mat image_prev, image_next;
std::vector<cv::Point> features_prev, features_next;

image_next = getImage();

// Obtain initial set of features
cv::goodFeaturesToTrack(image_next, // the image 
  features_next,   // the output detected features
  max_count,  // the maximum number of features 
  qlevel,     // quality level
  minDist     // min distance between two features
);

// Tracker is initialised and initial features are stored in features_next
// Now iterate through rest of images
for(;;)

    image_prev = image_next.clone();
    feature_prev = features_next;
    image_next = getImage();  // Get next image

    // Find position of feature in new image
    cv::calcOpticalFlowPyrLK(
      image_prev, image_next, // 2 consecutive images
      points_prev, // input point positions in first im
      points_next, // output point positions in the 2nd
      status,    // tracking success
      err      // tracking error
    );

    if ( stopTracking() ) break;

【讨论】:

我注意到您只进行一次特征检测。我已经测试了这段代码。我发现只能跟踪在第一张图像上检测到的特征。如果所有这些特征都超出了图像的范围,那么就没有要跟踪的特征了。我需要使用光流进行 3D 构建。那么我们如何在不断跟踪旧特征的同时添加新的图像特征呢?谢谢。 是的,您只检测带有goodFeaturesToTrack 的特征,然后光流方法简单地跟踪它们。如果要在每一帧中保持一定数量的特征,则必须检测有多少特征被成功跟踪到当前帧,然后尝试检测其他要跟踪到下一帧的特征。另一种方法是检测每一帧中的特征,然后计算描述符并使用this page 上的函数匹配这些描述符。 如果您需要更多详细信息,最好提出一个新问题。 由于我使用视频序列,我更喜欢使用光流进行特征匹配。如果我在每一帧中都检测到特征,那么这些特征将不会被稳定地跟踪,因为这次检测到的特征可能下次检测不到。谢谢回复。但我不明白如何“检测额外的”?例如,如果我在第一帧中检测到 100 个特征,现在视野中只有 50 个,我如何在保持旧的 50 个的同时检测到额外的 50 个特征?我认为唯一的解决方案是运行 goodFeaturesToTrack 来检测一组新的 100 个特征,对吧? 我已经发布了一个新问题:***.com/questions/10159236/…【参考方案2】:

cv::calcOpticalFlowPyrLK(..) 函数使用参数:

cv::calcOpticalFlowPyrLK(prev_gray, curr_gray, features_prev, features_next, status, err);

cv::Mat prev_gray, curr_gray;
std::vector<cv::Point2f> features_prev, features_next;
std::vector<uchar> status;
std::vector<float> err;

在下一帧中查找像素的最简单(部分)代码:

features_prev.push_back(cv::Point(4, 5));
cv::calcOpticalFlowPyrLK(prev_gray, curr_gray, features_prev, features_next, status, err);

如果像素被成功找到status[0] == 1features_next[0] 将在下一帧显示像素的坐标。此示例中可以找到值信息:OpenCV/samples/cpp/lkdemo.cpp

【讨论】:

以上是关于使用光流的 OpenCV 跟踪的主要内容,如果未能解决你的问题,请参考以下文章

如何使用opencv实现金字塔光流lk跟踪算法

如何在openCV python中将背景减法与密集光流跟踪相结合

运动目标检测——光流法与opencv代码实现

干货 | OpenCV中KLT光流跟踪原理详解与代码演示

基于 OpenCV 图像的光流场

OpenCV 接触光流的时间