Замедленное движение в C ++ - PullRequest
1 голос
/ 26 апреля 2019

Я хочу сделать медленное движение.Я видел реализацию здесь: 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 Ответ

1 голос
/ 26 апреля 2019

Алгоритм оптического потока не будет работать для ваших тестовых изображений.

Первая проблема заключается в том, что ваши тестовые изображения имеют очень небольшую разницу в значениях соседних пикселей.Эти полностью черные линии и один цветной квадрат не дают подсказки алгоритму оптического потока, где области изображения перемещаются, так как алгоритм не способен обрабатывать все изображение сразу и вычисляет оптический поток с небольшими 15x15 (как вы установили его в calcOpticalFlowFarneback) окно пикселей.

Вторая проблема заключается в том, что ваши тестовые изображения слишком сильно отличаются.Расстояние между позициями коричневого квадрата слишком велико.Опять же, Farneback не может его обнаружить.

Попробуйте код с некоторыми реальными видеокадрами или отредактируйте свои тесты, чтобы они были менее монотонными (установите некоторую текстуру в квадратные, фоновые и прямоугольные линии) и приблизьте квадратыдруг к другу на изображениях (попробуйте 2-10 пикселей).Вы также можете поиграть с 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);

Здесь направление потока пикселей будет представлено цветом (оттенок), а расстояние перемещения пикселей будет представлено яркостью.

Попробуйте использовать изображения, которые я создал:

enter image description here enter image description here.

Также обратите внимание, что код

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);
    }
}

С этим измененным кодом и моими тестами я получаю этот вывод:

enter image description here

...