opencv 如何计算Lucas Kanade流?

sqxo8psd  于 2023-03-23  发布在  其他
关注(0)|答案(1)|浏览(114)

我目前正在做一个物体跟踪的项目,已经使用了C++和OpenCV。我已经成功地使用Farneback密集光流实现了k means等分割方法(使用每帧中的位移)。现在我想用Lucas Kanade稀疏方法做同样的事情。但是这个函数的输出是:
nextPts -包含第二图像中输入特征的计算的新位置的2D点(具有单精度浮点坐标)的输出向量;传递OPTFLOW_USE_INITIAL_FLOW标志时,向量的大小必须与输入中的大小相同。
(as(官方网站)
我的问题是**我将如何获得Mat流的结果?**例如,我迄今已尝试:

// Implement Lucas Kanade algorithm
    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);

这是光流的演示。有什么想法,我应该如何得到一个垫流类似的结果法内贝克光流?
(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);

有什么想法吗?

jvidinwx

jvidinwx1#

要获得像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::calcOpticalFlowFarnebackcvShowImage在c++中应该是cv::imshow等等

更新

因为你需要的是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

相关问题