linux下基于c++使用opencv的cpu和gpu版本提取tvl1光流

使用opencv c++版本提取tvl1光流

  • 前言
  • Gpu版本
  • cpu版本
  • 配置文件及运行

前言

在计算机视觉中,光流可以用来反映视频中的信息,在行为识别,跟踪,视频分割等任务中都使用.对光流不了解的可以参考计算机视觉–光流法(optical flow)简介,本文的计算的光流是基于tvl1算法. 对于什么是tvl1光流,推荐大家参考啥是TV_L1 opticalFlow.对于在python中如何提取tvl1光流,大家可以参考python提取tvl1.本文所使用的环境如下:

opencv-4.5.1
ubuntu16.04
g++/gcc-5.4.0,
cmake-3.15.2 

ubuntu下编译安装opencv和opencv_contrib gpu版本可以参考OpenCV: Linux下编译GPU版本(4.2.0版本).

Gpu版本

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::cuda;

void convertFlowToImage(const Mat &flow, 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 < img_x.rows; ++i) {
        for (int j = 0; j < img_x.cols; ++j) {
            // float x = flow_x.at(i,j);
            // float y = flow_y.at(i,j);
            img_x.at(i,j) = CAST(flow.at(i, j).x, lowerBound, higherBound);
            img_y.at(i,j) = CAST(flow.at(i, j).x, lowerBound, higherBound);
        }
    }
#undef CAST
}
int main(int argc, char * argv[]){
    vector flow;
    //记得改文件路径
    const char* path = "path_to_video";
    GpuMat prev_gray, curr_gray, d_flow, cu_dst_y, cu_dst_x;
    Mat prev, curr, frame;
    Ptr alg_tvl1 = cuda::OpticalFlowDual_TVL1::create();
    VideoCapture  capture(path);
    capture.read(frame);
    cvtColor(frame, prev, CV_BGR2GRAY);
    prev_gray.create(prev.size(), CV_8UC1);
    curr_gray.create(prev.size(), CV_8UC1);
    int h = frame.rows; 
    int w = frame.cols;
    if(!capture.isOpened()){
        cout<<"Read video failed"<calc(prev_gray, curr_gray, d_flow);
        d_flow.download(cpu_flow);
        flow.push_back(cpu_flow);
        frameNum += 2;  //每隔一帧计算光流
        capture.set(CAP_PROP_POS_FRAMES, frameNum);
        prev = curr.clone();
        num++;
    }
	//记得改路径
    char* save_dir = "save_path_for_flow";
    int save_dir_len = strlen(save_dir);
    for(int i = 0; i < flow.size(); i++){
        Mat img_x(h, w, CV_8UC1);
        Mat img_y(h, w, CV_8UC1);
        convertFlowToImage(flow[i], img_x, img_y, -15, 15);
        char y_path[save_dir_len + 1 + 19];
        sprintf(y_path, "%s%s%s%06d%s", save_dir, "/", "y_frame_", i, ".jpg");
        char x_path[save_dir_len + 1 + 19];  
        sprintf(x_path, "%s%s%s%06d%s", save_dir, "/", "x_frame_", i, ".jpg");
        imwrite(y_path, img_y);
        imwrite(x_path, img_x);
    }
    end = clock();
    cout<<"total frames: " << num << endl;
    cout<< "time used: " << (double)(end - begin) / CLOCKS_PER_SEC << endl;
    return 0;
}

cpu版本

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::cuda;

void convertFlowToImage(const Mat &flow, 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 < img_x.rows; ++i) {
        for (int j = 0; j < img_x.cols; ++j) {
            img_x.at(i,j) = CAST(flow.at(i, j).x, lowerBound, higherBound);
            img_y.at(i,j) = CAST(flow.at(i, j).x, lowerBound, higherBound);
        }
    }
#undef CAST
}
int main(int argc, char * argv[]){
    vector flow;
    //记得改文件路径
    const char* path = "path_to_video";
    Mat prev, curr, frame;
    cv::Ptr alg_tvl1 = cv::optflow::DualTVL1OpticalFlow::create();
    VideoCapture  capture(path);
    capture.read(frame);
    cvtColor(frame, prev, CV_BGR2GRAY);
    int h = frame.rows; 
    int w = frame.cols;
    if(!capture.isOpened()){
        cout<<"Read video failed"<calc(prev, curr, d_flow);
        flow.push_back(d_flow);
        frameNum += 2; //每隔一帧计算光流
        capture.set(CAP_PROP_POS_FRAMES, frameNum);
        prev = curr.clone();
        num++;
    }
    //记得改路径
    char* save_dir = "save_path_for_flow";
    int save_dir_len = strlen(save_dir);
    for(int i = 0; i < flow.size(); i++){
        Mat img_x(h, w, CV_8UC1);
        Mat img_y(h, w, CV_8UC1);
        convertFlowToImage(flow[i], img_x, img_y, -15, 15);
        char y_path[save_dir_len + 1 + 19];
        sprintf(y_path, "%s%s%s%06d%s", save_dir, "/", "y_frame_", i, ".jpg");
        char x_path[save_dir_len + 1 + 19];  
        sprintf(x_path, "%s%s%s%06d%s", save_dir, "/", "x_frame_", i, ".jpg");
        imwrite(y_path, img_y);
        imwrite(x_path, img_x);
    }
    end = clock();
    cout<<"total frames: " << num << endl;
    cout<< "time used: " << (double)(end - begin) / CLOCKS_PER_SEC << endl;
    return 0;
}

配置文件及运行

CMakeLists.txt文件内容

cmake_minimum_required(VERSION 2.8)
project(text)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -O3 -std=c++11 -fopenmp")
find_package(CUDA QUIET REQUIRED)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
cuda_add_executable(test test.cpp)
target_link_libraries(test ${OpenCV_LIBS})

进入CMakeLists.txt文件所在路径

camek .
make

此时会生成一个test的可执行文件,然后运行

./test

如果没有报错,即可在指定的保存目录下看到生成的光流图.

代码参考:
https://github.com/yjxiong/dense_flow

你可能感兴趣的:(linux下基于c++使用opencv的cpu和gpu版本提取tvl1光流)