1

我想做慢动作。我在这里看到了一个实现:https ://github.com/vaibhav06891/SlowMotion

我修改了代码只生成一帧。

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/tracking.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <string>
using namespace cv;
using namespace std;


#define CLAMP(x,min,max) (  ((x) < (min)) ? (min) : ( ((x) > (max)) ? (max) : (x) )  )

int main(int argc, char** argv)
{
    Mat frame,prevframe;
    prevframe = imread("img1.png");
    frame = imread("img2.png");

    Mat prevgray, gray;
    Mat fflow,bflow;

    Mat flowf(frame.rows,frame.cols ,CV_8UC3);   // the forward co-ordinates for interpolation
    flowf.setTo(Scalar(255,255,255));
    Mat flowb(frame.rows,frame.cols ,CV_8UC3);   // the backward co-ordinates for interpolation
    flowb.setTo(Scalar(255,255,255));
    Mat final(frame.rows,frame.cols ,CV_8UC3);

    int fx,fy,bx,by;

    cvtColor(prevframe,prevgray,COLOR_BGR2GRAY);  // Convert to gray space for optical flow calculation
    cvtColor(frame, gray, COLOR_BGR2GRAY);
    calcOpticalFlowFarneback(prevgray, gray, fflow, 0.5, 3, 15, 3, 3, 1.2, 0);  // forward optical flow
    calcOpticalFlowFarneback(gray, prevgray, bflow, 0.5, 3, 15, 3, 3, 1.2, 0);   //backward optical flow

    for (int y=0; y<frame.rows; y++) 
    {
        for (int x=0; x<frame.cols; x++) 
        {
            const Point2f fxy = fflow.at<Point2f>(y,x);
            fy = CLAMP(y+fxy.y*0.5,0,frame.rows);
            fx = CLAMP(x+fxy.x*0.5,0,frame.cols);

            flowf.at<Vec3b>(fy,fx) = prevframe.at<Vec3b>(y,x);

            const Point2f bxy = bflow.at<Point2f>(y,x);
            by = CLAMP(y+bxy.y*(1-0.5),0,frame.rows);
            bx = CLAMP(x+bxy.x*(1-0.5),0,frame.cols);
            flowb.at<Vec3b>(by,bx) = frame.at<Vec3b>(y,x);                  
        }
    }                   
    final = flowf*(1-0.5) + flowb*0.5;  //combination of frwd and bckward martrix
    cv::medianBlur(final,final,3);
    imwrite( "output.png",final);
    return 0;
}

但结果并不如预期。

对于图像:

在此处输入图像描述 在此处输入图像描述

结果是: 在此处输入图像描述

有谁知道是什么问题?

4

1 回答 1

1

光流算法不适用于您的测试图像。

第一个问题是您的测试图像在相邻像素值方面几乎没有差异。完全黑线和单一颜色方块没有为光流算法提供任何线索,其中图像区域移动,因为算法无法一次处理整个图像,并用小 15x15(如您设置的那样calcOpticalFlowFarneback)像素计算光流窗户。

第二个问题是您的测试图像差异太大。棕色方块位置之间的距离太大。Farneback 再次无法检测到它。

尝试使用一些现实生活中的视频帧的代码或编辑您的测试以使其不那么单调(为正方形、背景和矩形线设置一些纹理)并使图像上的正方形彼此靠近(尝试 2-10 px 距离)。您还可以根据您的条件使用calcOpticalFlowFarneback参数(请阅读此处)。

您可以使用此代码将获得的光流保存到图像以进行调试:

Mat debugImage = Mat::zeros(fflow.size(), CV_8UC3);
float hsvHue, magnitude;

for (int x = 0; x < fflow.cols; x++)
{
    for (int y = 0; y < fflow.rows; y++)
    {
        auto& item = fflow.at<Vec2f>(y, x);
        magnitude = sqrtf(item[0] * item[0] + item[1] * item[1]);
        hsvHue = atan2f(item[1], item[0]) / static_cast<float>(CV_PI)* 180.f;
        // div 2 to fit 0..255 range
        hsvHue = (hsvHue >= 0. ? hsvHue : (360.f + hsvHue)) / 2.f;
        debugImage.at<Vec3b>(y, x)[0] = static_cast<uchar>(hsvHue);
        debugImage.at<Vec3b>(y, x)[1] = 255;
        debugImage.at<Vec3b>(y, x)[2] = static_cast<uchar>(255.f * magnitude);
    }
}
cvtColor(debugImage, debugImage, CV_HSV2BGR);
imwrite("OpticalFlow.png", debugImage);

这里像素流向用颜色(色调)表示,像素移动距离用亮度表示。

尝试使用我创建的这些图像:

在此处输入图像描述 在此处输入图像描述.

另请注意

for (int y = 0; y < frame.rows; y++)
{
    for (int x = 0; x < frame.cols; x++)
    {
        const Point2f fxy = fflow.at<Point2f>(y, x);
        fy = CLAMP(y + fxy.y*0.5, 0, frame.rows);
        fx = CLAMP(x + fxy.x*0.5, 0, frame.cols);

        flowf.at<Vec3b>(fy, fx) = prevframe.at<Vec3b>(y, x);
        ...

代码不会flowf对移动到的一些没有对应目标位置的像素进行着色,而光流算法可以产生这种情况。我会将其更改为:

for (int y = 0; y < frame.rows; y++)
{
    for (int x = 0; x < frame.cols; x++)
    {
        const Point2f fxy = fflow.at<Point2f>(y, x);
        fy = CLAMP(y - fxy.y*0.5, 0, frame.rows);
        fx = CLAMP(x - fxy.x*0.5, 0, frame.cols);
        flowf.at<Vec3b>(y, x) = prevframe.at<Vec3b>(fy, fx);

        const Point2f bxy = bflow.at<Point2f>(y, x);
        by = CLAMP(y - bxy.y*(1 - 0.5), 0, frame.rows);
        bx = CLAMP(x - bxy.x*(1 - 0.5), 0, frame.cols);
        flowb.at<Vec3b>(y, x) = frame.at<Vec3b>(by, bx);
    }
}

有了这个更改的代码和我的测试,我得到了这个输出:

在此处输入图像描述

于 2019-04-26T14:29:35.750 回答