使用光流进行OpenCV跟踪

18

我将此用作跟踪算法的基础功能。

    //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 光流函数计算出这个像素在下一帧图像上的位置呢?

2个回答

29

当你使用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;
}

1
我注意到你只对一个时间进行了特征检测。我已经测试过这段代码,发现只有第一张图像上检测到的特征才能被跟踪。如果所有这些特征超出了图像范围,就没有特征可供跟踪了。我需要使用光流进行三维重建。那么我们如何持续跟踪旧特征并同时添加新图像特征呢?谢谢。 - Shiyu
1
是的,您只需使用goodFeaturesToTrack检测特征,然后光流方法会简单地跟踪它们。如果您想在每个帧中保持一定数量的特征,则需要检测成功跟踪到当前帧的特征数量,然后尝试检测其他要跟踪到下一帧的特征。另一种选择是在每个帧中检测特征,然后使用此页面上的函数计算描述符并匹配这些描述符。 - Chris
如果您需要更多细节,最好提出一个新问题。 - Chris
由于我处理视频序列,所以我更喜欢使用光流进行特征匹配。如果我在每一帧中检测特征,那么这些特征将无法稳定跟踪,因为本次检测到的特征可能下次就检测不到了。谢谢回复。但是我不明白如何“检测到额外的特征”?例如,如果我在第一帧中检测到100个特征,现在视野中只有50个,那么如何在保留旧的50个的同时检测到另外50个特征呢?我认为唯一的解决方案是运行goodFeaturesToTrack来检测一个新的100个特征集,对吗? - Shiyu
我已经发布了一个关于这个问题的新问题:https://dev59.com/bmkw5IYBdhLWcg3wEmab#10172247 - Shiyu

1

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接