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

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

前言

在计算机视觉中,光流可以用来反映视频中的信息,在行为识别,跟踪,视频分割等任务中都使用.对光流不了解的可以参考计算机视觉–光流法(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<cuda_runtime.h>
#include<device_launch_parameters.h>
#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
#include<opencv2/core.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/core/cuda.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<opencv2/cudaarithm.hpp>
#include<opencv2/cudaoptflow.hpp>
#include<opencv2/cudacodec.hpp>
#include<opencv2/highgui/highgui_c.h>
#include<opencv2/cudaoptflow.hpp>
#include<time.h>
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<float>(i,j);
            // float y = flow_y.at<float>(i,j);
            img_x.at<uchar>(i,j) = CAST(flow.at<Point2f>(i, j).x, lowerBound, higherBound);
            img_y.at<uchar>(i,j) = CAST(flow.at<Point2f>(i, j).x, lowerBound, higherBound);
        }
    }
#undef CAST
}
int main(int argc, char * argv[]){
    vector<Mat> 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<cuda::OpticalFlowDual_TVL1> 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"<<endl;
        return -1;
    }
    cu_dst_x = cuda::GpuMat(h, w, CV_8UC1, Scalar(0));
    cu_dst_y = cuda::GpuMat(h, w, CV_8UC1, Scalar(0));
    clock_t begin, end;
    begin = clock();
    int frameNum = 2;
    capture.set(CAP_PROP_POS_FRAMES, frameNum);
    int num = 0;
    while(capture.read(frame)){
        Mat cpu_flow;
        cvtColor(frame, curr, CV_BGR2GRAY);
        prev_gray.upload(prev);
        curr_gray.upload(curr);
        alg_tvl1->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<device_launch_parameters.h>
#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
#include<opencv2/core.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<opencv2/highgui/highgui_c.h>
#include<opencv2/optflow.hpp>
#include<time.h>
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<uchar>(i,j) = CAST(flow.at<Point2f>(i, j).x, lowerBound, higherBound);
            img_y.at<uchar>(i,j) = CAST(flow.at<Point2f>(i, j).x, lowerBound, higherBound);
        }
    }
#undef CAST
}
int main(int argc, char * argv[]){
    vector<Mat> flow;
    //记得改文件路径
    const char* path = "path_to_video";
    Mat prev, curr, frame;
    cv::Ptr<cv::optflow::DualTVL1OpticalFlow> 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"<<endl;
        return -1;
    }
    clock_t begin, end;
    begin = clock();
    int frameNum = 2;
    capture.set(CAP_PROP_POS_FRAMES, frameNum);
    int num = 0;
    while(capture.read(frame)){
        Mat d_flow;
        cvtColor(frame, curr, CV_BGR2GRAY);
        alg_tvl1->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

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值