输入的参数有:
-f 视频文件名称
-x x方向光流文件前缀
-y y方向光流文件前缀
-i rgb图像文件前缀
-b 约束距离
-t 光流提取算法类别(0- 1-)
-o 输出格式
std::vector<std::vector<uchar> > out_vec_x, out_vec_y, out_vec_img;
calcDenseFlow(vidFile, bound, type, 1,
out_vec_x, out_vec_y, out_vec_img);
if (output_style == "dir") {
writeImages(out_vec_x, xFlowFile);
writeImages(out_vec_y, yFlowFile);
writeImages(out_vec_img, imgFile);
}else{
// LOG(INFO)<<"Writing results to Zip archives";
writeZipFile(out_vec_x, "x_%05d.jpg", xFlowFile+".zip");
writeZipFile(out_vec_y, "y_%05d.jpg", yFlowFile+".zip");
writeZipFile(out_vec_img, "img_%05d.jpg", imgFile+".zip");
}
根据输入的视频文件名称,定义一个视频捕获对象video_stream读取视频。定义五个vector变量。
capture_frame-------t时刻捕获的帧
capture_image-------t时刻运动图片
capture_gray---------t时刻运动图片的灰度化
pre_image-------------t-1时刻运动图片
pre_gray---------------t-1时刻运动图片灰度化
读取视频帧到capture_frame中,如果是第一帧则进行初始化,给以上五个变量分配给capture_frame大小内存。并将读取的第一帧赋值给pre_image并灰度化后赋值给pre_gay。从第二帧开始,计算前一帧和当前帧之前的光流,并存储在flow中,有两种光流计算算法。将计算出的光流split分成x和y两个方向的光流,先将光流转化为图片形式,再接着其编码成数据流,存储在str_x和str_y中。对capture_image直接编码成数据流存储在str_img中。接着将这三个流分别加到对应的流向量中,最后视频每一时刻的RGB图像和X、Y光流数据存储在out_vec_x,out_vec_y,out_vec_img。读取这些向量,将数据流分别写进图片中,一个视频光流提取完成。
void calcDenseFlow(std::string file_name, int bound, int type, int step,
std::vector<std::vector<uchar> >& output_x,
std::vector<std::vector<uchar> >& output_y,
std::vector<std::vector<uchar> >& output_img){
#读取file_name视频文件
VideoCapture video_stream(file_name);
CHECK(video_stream.isOpened())<<"Cannot open video stream \""
<<file_name
<<"\" for optical flow extraction.";
Mat capture_frame, capture_image, prev_image, capture_gray, prev_gray;
Mat flow, flow_split[2];
//定义一个DualTVL对象
cv::Ptr<cv::DualTVL1OpticalFlow> alg_tvl1 = cv::createOptFlow_DualTVL1();
bool initialized = false;
for(int iter = 0;; iter++){
//将视频帧读取到Mat中矩阵中
video_stream >> capture_frame;
if (capture_frame.empty()) break; // read frames until end
//build mats for the first frame
if (!initialized){Mat
//根据capture_frame,创建同等大小的四个
initializeMats(capture_frame, capture_image, capture_gray,
prev_image, prev_gray);
//将当前帧赋值给pre_image
capture_frame.copyTo(prev_image);
//对prev_image灰度化后赋值给pre_gray
cvtColor(prev_image, prev_gray, CV_BGR2GRAY);
initialized = true;
// LOG(INFO)<<"Initialized";
}else if(iter % step == 0){
//将获取的帧数据传给capture_image,并进行灰度转换
capture_frame.copyTo(capture_image);
cvtColor(capture_image, capture_gray, CV_BGR2GRAY);
switch(type){
case 0: {
//Gunnar Farneback算法基于图像梯度恒定假设和局部光流恒定假设。
calcOpticalFlowFarneback(prev_gray, capture_gray, flow,
0.702, 5, 10, 2, 7, 1.5,
cv::OPTFLOW_FARNEBACK_GAUSSIAN );
break;
}
case 1: {
//使用python自带的TVL提取光流
alg_tvl1->calc(prev_gray, capture_gray, flow);
break;
}
default:
LOG(WARNING)<<"Unknown optical method. Using Farneback";
calcOpticalFlowFarneback(prev_gray, capture_gray, flow,
0.702, 5, 10, 2, 7, 1.5,
cv::OPTFLOW_FARNEBACK_GAUSSIAN );
}
//定义数据流
std::vector<uchar> str_x, str_y, str_img;
//将光流分成x、y方向存在flow_split中
split(flow, flow_split);
//对光流、rgb图片编码成数据流
encodeFlowMap(flow_split[0], flow_split[1], str_x, str_y, bound);
imencode(".jpg", capture_image, str_img);
output_x.push_back(str_x);
output_y.push_back(str_y);
output_img.push_back(str_img);
//更新pre_image、pre_gray
std::swap(prev_gray, capture_gray);
std::swap(prev_image, capture_image);
}
}
}
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
}
void encodeFlowMap(const Mat& flow_map_x, const Mat& flow_map_y,
std::vector<uchar>& encoded_x, std::vector<uchar>& encoded_y,
int bound, bool to_jpg){
Mat flow_img_x(flow_map_x.size(), CV_8UC1);
Mat flow_img_y(flow_map_y.size(), CV_8UC1);
convertFlowToImage(flow_map_x, flow_map_y, flow_img_x, flow_img_y,
-bound, bound);
if (to_jpg) {
//将cv2:mat数据flow_img_x转化为数据流存储到encoded_x中
imencode(".jpg", flow_img_x, encoded_x);
imencode(".jpg", flow_img_y, encoded_y);
}else {
encoded_x.resize(flow_img_x.total());
encoded_y.resize(flow_img_y.total());
memcpy(encoded_x.data(), flow_img_x.data, flow_img_x.total());
memcpy(encoded_y.data(), flow_img_y.data, flow_img_y.total());
}
}
//截取extract_flow
if (output_style == "dir") {
writeImages(out_vec_x, xFlowFile);
writeImages(out_vec_y, yFlowFile);
writeImages(out_vec_img, imgFile);
}else{
// LOG(INFO)<<"Writing results to Zip archives";
writeZipFile(out_vec_x, "x_%05d.jpg", xFlowFile+".zip");
writeZipFile(out_vec_y, "y_%05d.jpg", yFlowFile+".zip");
writeZipFile(out_vec_img, "img_%05d.jpg", imgFile+".zip");
}
//输入数据流及文件前缀
void writeImages(std::vector<std::vector<uchar>> images, std::string name_temp){
for (int i = 0; i < images.size(); ++i){
char tmp[256];
sprintf(tmp, "_%05d.jpg", i+1);
FILE* fp;
fp = fopen((name_temp + tmp).c_str(), "wb");
fwrite( images[i].data(), 1, images[i].size(), fp);
fclose(fp);
}
}