C ++中的慢动作

时间:2019-04-26 12:28:41

标签: c++ opencv slowmotion

我想慢动作。我在这里看到了一个实现: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;
}

但是结果与预期不符。

对于图像:

enter image description here enter image description here

结果是: enter image description here

有人知道是什么问题吗?

1 个答案:

答案 0 :(得分:1)

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

第一个问题是您的测试图像的相邻像素值差异很小。完全黑色的线条和单一的颜色方块不会为光流算法提供任何线索,光流算法无法移动图像区域,因为该算法无法一次处理整个图像,并且无法以15x15的小像素来计算光流(如您在{{ 1}})像素窗口。

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

尝试使用一些真实的视频帧进行编码,或将测试编辑得不太单调(为正方形,背景和矩形线设置一些纹理),并使图像上的正方形彼此靠得更近(尝试2-10像素)距离)。您还可以根据自己的条件使用calcOpticalFlowFarneback个自变量(读为here)。

您可以使用以下代码来保存获取到图像的光流以进行调试:

calcOpticalFlowFarneback

此处的像素流动方向将用颜色(色相)表示,而像素移动距离将以亮度表示。

尝试使用我创建的这张图片:

enter image description here enter image description here

还要注意

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

使用更改后的代码和测试,我得到以下输出:

enter image description here