wanglimin / dense_flow

OpenCV Implementation of different optical flow algorithms
231 stars 202 forks source link

denseFlow_GPU with OpenCV 3.4.6 #41

Closed FantasyJXF closed 4 years ago

FantasyJXF commented 4 years ago

Install the OpenCV with CUDA and use the following code to get optical flow

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/cuda.hpp"
#include "opencv2/cudaoptflow.hpp"
#include "opencv2/cudaarithm.hpp"

#include <stdio.h>
#include <string>
#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::cuda;

static void convertFlowToImage(const Mat &flow_x, const Mat &flow_y, Mat &img_x, Mat &img_y,
       double lowerBound, double higherBound) {
    #define CAST(v, L, H) ((v) > (H) ? 255 : (v) < (L) ? 0 : cvRound(255*((v) - (L))/((H)-(L))))
    for (int i = 0; i < flow_x.rows; ++i) {
        for (int j = 0; j < flow_y.cols; ++j) {
            float x = flow_x.at<float>(i,j);
            float y = flow_y.at<float>(i,j);
            img_x.at<uchar>(i,j) = CAST(x, lowerBound, higherBound);
            img_y.at<uchar>(i,j) = CAST(y, lowerBound, higherBound);
        }
    }
    #undef CAST
}

static void drawOptFlowMap(const Mat& flow, Mat& cflowmap, int step,double, const Scalar& color){
    for(int y = 0; y < cflowmap.rows; y += step)
        for(int x = 0; x < cflowmap.cols; x += step)
        {
            const Point2f& fxy = flow.at<Point2f>(y, x);
            line(cflowmap, Point(x,y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)),
                 color);
            circle(cflowmap, Point(x,y), 2, color, -1);
        }
}

int main(int argc, char** argv){
    // IO operation
    //const char* keys =
//          {
//          "{ f  | vidFile      | ex2.avi | filename of video }"
//          "{ x  | xFlowFile    | flow_x | filename of flow x component }"
//          "{ y  | yFlowFile    | flow_y | filename of flow x component }"
//          "{ i  | imgFile      | flow_i | filename of flow image}"
//          "{ b  | bound | 15 | specify the maximum of optical flow}"
//          "{ t  | type | 0 | specify the optical flow algorithm }"
//          "{ d  | device_id    | 0  | set gpu id}"
//          "{ s  | step  | 1 | specify the step for frame sampling}"
//      };

  const cv::String keys =
      "{@vidFile     | | filename of video }"
      "{@xFlowFile   | | filename of flow x component }"
      "{@yFlowFile   | | filename of flow x component }"
      "{@imgFile     | | filename of image component }"
      "{@bound       | 15 | specify the maximum of optical flow}"
      "{@type        | 0 | specify the optical flow algorithm }"
      "{@device_id   | 0 | set gpu id }"
      "{@step        | 1 | specify the step for frame sampling}"
      ;

    cv::CommandLineParser cmd(argc, argv, keys);
    std::string vidFile = cmd.get<string>("@vidFile");
    std::string xFlowFile = cmd.get<string>("@xFlowFile");
    std::string yFlowFile = cmd.get<string>("@yFlowFile");
    std::string imgFile = cmd.get<string>("@imgFile");
    int bound = cmd.get<int>("@bound");
    int type  = cmd.get<int>("@type");
    int device_id = cmd.get<int>("@device_id");
    int step = cmd.get<int>("@step");

    cv::VideoCapture capture(vidFile);
    if(!capture.isOpened()) {
        printf("Could not initialize capturing..\n");
        return -1;
    }

    int frame_num = 0;
    Mat image, prev_image, prev_grey, grey, frame, flow, flows[2];
    GpuMat frame_0, frame_1, gflow;

    setDevice(device_id);
    cv::Ptr<cv::cuda::FarnebackOpticalFlow> alg_farn;
    cv::Ptr<cv::cuda::OpticalFlowDual_TVL1> alg_tvl1;
    cv::Ptr<cv::cuda::BroxOpticalFlow> alg_brox;

    while(true) {
        capture >> frame;
        if(frame.empty())
            break;
        if(frame_num == 0) {
            image.create(frame.size(), CV_8UC3);
            grey.create(frame.size(), CV_8UC1);
            prev_image.create(frame.size(), CV_8UC3);
            prev_grey.create(frame.size(), CV_8UC1);

            frame.copyTo(prev_image);
            cvtColor(prev_image, prev_grey, CV_BGR2GRAY);

            frame_num++;

            int step_t = step;
            while (step_t > 1){
                capture >> frame;
                step_t--;
            }
            continue;
        }

        frame.copyTo(image);
        cvtColor(image, grey, CV_BGR2GRAY);

        frame_0.upload(prev_grey);
        frame_1.upload(grey);

        // GPU optical flow
        switch(type){
        case 0:
            alg_farn = cv::cuda::FarnebackOpticalFlow::create();
            alg_farn->calc(frame_0,frame_1, gflow);
            break;
        case 1:
            alg_tvl1 = cv::cuda::OpticalFlowDual_TVL1::create();
            alg_tvl1->calc(frame_0,frame_1, gflow);
            break;
        case 2:
            alg_brox = cv::cuda::BroxOpticalFlow::create(0.197f, 50.0f, 0.8f, 10, 77, 10);
            GpuMat d_frame0f, d_frame1f;
            frame_0.convertTo(d_frame0f, CV_32F, 1.0 / 255.0);
            frame_1.convertTo(d_frame1f, CV_32F, 1.0 / 255.0);
            alg_brox->calc(d_frame0f, d_frame1f, gflow);
            break;
        }

        gflow.download(flow);
        cv::split(flow, flows);

        // Output optical flow
        Mat imgX(flows[0].size(),CV_8UC1);
        Mat imgY(flows[1].size(),CV_8UC1);
        convertFlowToImage(flows[0],flows[1], imgX, imgY, -bound, bound);
        char tmp[20];
        sprintf(tmp,"_%05d.jpg",int(frame_num));

        // Mat imgX_, imgY_, image_;
        // resize(imgX,imgX_,cv::Size(340,256));
        // resize(imgY,imgY_,cv::Size(340,256));
        // resize(image,image_,cv::Size(340,256));

        imwrite(xFlowFile + tmp,imgX);
        imwrite(yFlowFile + tmp,imgY);
        imwrite(imgFile + tmp, image);

        std::swap(prev_grey, grey);
        std::swap(prev_image, image);
        frame_num = frame_num + 1;

        int step_t = step;
        while (step_t > 1){
            capture >> frame;
            step_t--;
        }
    }
    return 0;
}

The command I use is :

./denseFlow_gpu --vidFile /home/Datasets/video/UCF-101/TaiChi/v_TaiChi_g25_c04.avi --xFlowFile tmp/flow_x --yFlowFile tmp/flow_x --imgFile tmp/image --bound 20 --type 1 --evice_id 0 --step 1

Here my question is about the command line --xFlowFile tmp/flow_x --yFlowFile tmp/flow_x, why the flow in x/y direction result in the same file?

FantasyJXF commented 4 years ago

Obviously, --yFlowFile tmp/flow_y