在计算机视觉中,光流可以用来反映视频中的信息,在行为识别,跟踪,视频分割等任务中都使用.对光流不了解的可以参考计算机视觉–光流法(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版本).
#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;
}
#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