【问题标题】:How to compute Lucas Kanade flow如何计算 Lucas Kanade 流量
【发布时间】:2016-07-23 19:34:50
【问题描述】:

我目前正在从事一个对象跟踪项目,并使用过 c++ 、 opencv 。我已经成功使用 Farneback 密集光流来实现分割方法,例如 k 均值(使用每帧中的位移)。现在我想用 Lucas Kanade 稀疏方法做同样的事情。但是这个函数的输出是:

nextPts – 2D 点的输出向量(具有单精度浮点坐标),包含第二张图像中输入特征的计算新位置;当传递 OPTFLOW_USE_INITIAL_FLOW 标志时,向量必须与输入中的大小相同。

(如官网所述)

例如,我的问题是 如何将结果转换为 Mat 流。到目前为止我已经尝试过:

//实现Lucas Kanade算法

cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2,
frame1_features, frame2_features, number_of_features,
optical_flow_window, 5, optical_flow_found_feature,
optical_flow_feature_error, optical_flow_termination_criteria,
0);
 // Calculate each feature point's coordinates in every frame 
 CvPoint p,q;
 p.x = (int) frame1_features[i].x;
 p.y = (int) frame1_features[i].y;

 q.x = (int) frame2_features[i].x;
 q.y = (int) frame2_features[i].y;
// Creating the arrows for imshow

angle = atan2((double) p.y - q.y, (double) p.x - q.x);
hypotenuse = sqrt(square(p.y - q.y) + square(p.x - q.x));

/* Here we lengthen the arrow by a factor of three. */

q.x = (int) (p.x - 3 * hypotenuse * cos(angle));
q.y = (int) (p.y - 3 * hypotenuse * sin(angle));

cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);

p.x = (int) (q.x + 9 * cos(angle + pi / 4));
p.y = (int) (q.y + 9 * sin(angle + pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int) (q.x + 9 * cos(angle - pi / 4));
p.y = (int) (q.y + 9 * sin(angle - pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);

allocateOnDemand(&framenew, frame_size, IPL_DEPTH_8U, 3);
cvConvertImage(frame1, framenew, CV_CVTIMG_FLIP);

cvShowImage("Optical Flow", framenew);

这是光流演示。任何想法我应该如何获得类似于 Farneback 光流结果的 Mat 流?

(http://docs.opencv.org/2.4/modules/video/doc/motion_analysis_and_object_tracking.html#calcopticalflowfarneback)

更新:非常好的答案。但是现在我在显示 kmeans 图像时遇到了问题。我使用了farneback:

cv::kmeans(m, K, bestLabels,
                TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0),
                3, KMEANS_PP_CENTERS, centers);
        int colors[K];
        for (int i = 0; i < K; i++) {
            colors[i] = 255 / (i + 1);
        }

        namedWindow("Kmeans", WINDOW_NORMAL);

        Mat clustered = Mat(flow.rows, flow.cols, CV_32F);

        for (int i = 0; i < flow.cols * flow.rows; i++) {
            clustered.at<float>(i / flow.cols, i % flow.cols) =
                    (float) (colors[bestLabels.at<int>(0, i)]);
        }
        clustered.convertTo(clustered, CV_8U);
        imshow("Kmeans", clustered);

有什么想法吗? ?

【问题讨论】:

  • 不确定密集光学流使用的类型,但可能。某事像这样:对于 f1features 中的每个点和 f2features 中对应的 pt:map.at<:vec2f>(point) = cv::Vec2f(f2feature.x-f1feature.x, f2feature.y-f1feature.y)。将所有其他点设置为表示“未知 - 无法提取该像素的流”的值
  • 你说的最后一句话是什么意思?你能再解释一下吗?谢谢,我正在考虑类似的想法!
  • lucas kanade 计算了一个非常稀疏的流。因此,您的地图密集流中将有很多点您没有流信息。您必须决定为这些像素设置什么样的值。
  • @george_t 我为你的问题添加了一个可能的答案,以 cv 开头的函数名称通常是 opencv c 版本。在文档中你可以看到他们有C++: void calcOpticalFlowPyrLKC: void cvCalcOpticalFlowPyrLK。另外,我已经将 KMeans 直接用于 2D 新点,但我不确定您是要对新图像中的相似点(接近的点)进行聚类,还是对两个图像之间具有相似差异的点进行聚类,如果是稍后,只有一个带有差异的 cv::Point2f 向量将起作用
  • @george_t 好吧,你可以随时使用std::vector&lt;cv::Vec2f&gt;,在这里你可以放置每个点的位移。如果您希望 kmeans 考虑对象的初始位置或最终位置,也可以使用cv::Vec4f。甚至cv::Vec5f,如果您想在计算中包含强度。我会更新我的答案

标签: c++ opencv opticalflow


【解决方案1】:

要获得像 Farneback 算法这样的图像,您必须首先了解输出是什么。

在 OpenCV 文档中你有:

prev(y,x) ~ next(y + flow(y,x)[1], x +flow(y,x)[0])

因此,它是图像 1 和 2 之间的位移矩阵。假设您不计算的点将没有移动 0,0;你可以模拟这个,你只需要为每个点 (x,y) 放置新位置 (x', y'):

cv::Mat LKFlowMatrix(img.rows, img.cols, CV_32FC2, cv::Scalar(0,0));
LKFlowMatrix.at<cv::Vec2f>(y,x) = cv::Vec2f(x-x', y-y') ;

另外,不要忘记过滤状态 = 0 的“未找到点”

顺便说一句,你的函数不是它的opencv c++版本:

cvCalcOpticalFlowPyrLK 在 C++ 中应该是 cv::calcOpticalFlowFarneback cvShowImage应该是cv::imshowc++ 等等

** 更新 **

由于您需要的是 kmeans 的输入(我想这是 OpenCV 版本),并且您只想使用稀疏点,那么您可以执行以下操作:

cv::Mat prevImg, nextImg;
// load your images

std::vector<cv:Point2f> initial_points, new_points;
// fill the initial points vector 

std::vector<uchar> status;
std::vector<float> error;

cv::calcOpticalFlowPyrLK(prevImage, nextImage, initial_points, new_points, status, errors);

std::vector<cv::Vec2f> vectorForKMeans;
for(size_t t = 0; t < status.size(); t++){
  if(status[t] != 0)
    vectorForKmeans.push_back(cv::Vec2f(initial_points[i] - new_points[i]));
}

// Do kmeans to vectorForKMeans

【讨论】:

  • @george_t 那应该在另一个问题中,它是相关的,但它不是问题的主题......无论如何,您可以将Vec2f 或点或点的向量传递给kmeans垫。此外,输出可以是一个垫子、标签向量(如果我没记错的话是 int)。而labels[i] 将对应于vectorForKmeans[i],因此您可以使用colors[labels[i]] 之类的东西为点i 着色
  • @api55 如果使用 farneback 算法而不是 lucas kanade 算法,如何对这些数据执行 k 均值?
  • @MMahdiChamseddine 在问题中,最后一次更新显示了当他有 farneback 时 OP 使用了什么... kmeans 接受 cv::Mat 所以你也可以传递一个密集的结果
猜你喜欢
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
  • 2016-04-15
  • 2014-07-30
  • 1970-01-01
相关资源
最近更新 更多