基于calcOpticalFlowFarneback的OpenCV变形图像

Goz*_*Goz 9 c++ opencv opticalflow image-stabilization

我正在尝试使用Dense Optical Flow执行复杂的图像扭曲(我试图将第二个图像切换成与第一个图像大致相同的形状).我可能会把这一切都搞错了但是我发布了我尝试过的内容:

cv::Mat flow;
cv::calcOpticalFlowFarneback( mGrayFrame1, mGrayFrame2, flow, 0.5, 3, 15, 3, 5, 1.2, 0 );

cv::Mat newFrame = cv::Mat::zeros( frame.rows, frame.cols, frame.type() );
cv:remap( frame, newFrame, flow, cv::Mat(), CV_INTER_LINEAR );
Run Code Online (Sandbox Code Playgroud)

如果我正在计算2个灰度帧的流量垫的想法.我找回了一个似乎有意义的流垫,但现在我正在尝试使用此流信息重新映射我的原始(即非灰度)图像.

我认为重映射功能是我想要的,但是我得到了一个非常严重失真的图像.我的所有颜色信息都没有存在.我最终得到的橙色和黑色图像与我的原始图像有很小的相似之处.

我猜我错误地理解了重映射功能,它要么不做我想做的事情,要么就是因为我传入的内容出了问题.

如果前者有人对我如何解决这个问题有任何建议?如果是后者,我错了什么?

任何帮助非常感谢!

jet*_*t47 15

该remap功能不适用于光流.该函数remap使用指定的映射转换源图像:

dst(x, y) = src(mapx(x, y), mapy(x, y))
Run Code Online (Sandbox Code Playgroud)

光流有另一个公式:

frame1(x, y) = frame2(x + flowx(x, y), y + flowy(x, y))
Run Code Online (Sandbox Code Playgroud)

因此,remap首先使用函数,您需要从流创建一个映射:

Mat flow; // backward flow
calcOpticalFlowFarneback(nextFrame, prevFrame, flow);

Mat map(flow.size(), CV_32FC2);
for (int y = 0; y < map.rows; ++y)
{
    for (int x = 0; x < map.cols; ++x)
    {
        Point2f f = flow.at<Point2f>(y, x);
        map.at<Point2f>(y, x) = Point2f(x + f.x, y + f.y);
    }
}

Mat newFrame;
remap(prevFrame, newFrame, map);
Run Code Online (Sandbox Code Playgroud)

  • 注意使用向后流,即从`nextFrame`到`prevFrame`.这是必要的,因为流向量是针对源像素给出的("这里去了哪里"),而我们对目标像素感兴趣("这来自哪里"). (4认同)