├── README.md ├── compile_gpu.sh ├── denseFlow_gpu ├── denseFlow_gpu.cpp └── ex.avi /README.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | This repo is for using GPU to extract videos' dense optical flow fields. 3 | 4 | ## Authorship 5 | The code is mainly borrowed from [Limin Wang's repo](https://github.com/wanglimin/dense_flow). 6 | I've slightly changed the interface to facilitate my own usage. 7 | 8 | ## Interface 9 | Option | Name | Default | Note 10 | :--- | :--- | :--- | :--- 11 | f | vidFile | ex.avi | filename of video 12 | x | xFlowFile | x | filename prefix of flow x component 13 | y | yFlowFile | y | filename prefix of flow x component 14 | i | imgFile | i | filename prefix of image 15 | b | bound | 20 | specify the maximum (px) of optical flow 16 | t | type | 1 | specify the optical flow algorithm 17 | d | device_id | 0 | specify gpu id 18 | s | step | 1 | specify the step for frame sampling 19 | h | height | 0 | specify the height of saved flows, 0: keep original height 20 | w | width | 0 | specify the width of saved flows, 0: keep original width 21 | 22 | ## Example 23 | ``` 24 | mkdir flow 25 | ./denseFlow_gpu -f ex.avi -x flow/x -y flow/y -i flow/i -b 20 -t 1 -d 0 -s 1 -h 0 -w 0 26 | ``` 27 | > ex.avi is the input video 28 | > flow/ is the folder containing the extracted RGB frames and optical flows 29 | 30 | ## Notes 31 | 32 | * The RGB frames and optical flows are extracted at the original video resolution (Height, Width, FPS). 33 | * To extract optical flows at a different resolution, I recommend (1) reformat the video to that resolution, (2) extract frames/flows using this repo. 34 | * Options -h & -w controls the resolution of stored frames/flows. 35 | 36 | 37 | -------------------------------------------------------------------------------- /compile_gpu.sh: -------------------------------------------------------------------------------- 1 | g++ denseFlow_gpu.cpp -o denseFlow_gpu -lopencv_gpu `pkg-config --cflags --libs opencv` 2 | -------------------------------------------------------------------------------- /denseFlow_gpu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangwangx/denseFlow_gpu/a3d4d4e893689374637e8ce7cfda7c05be7131a9/denseFlow_gpu -------------------------------------------------------------------------------- /denseFlow_gpu.cpp: -------------------------------------------------------------------------------- 1 | #include "opencv2/video/tracking.hpp" 2 | #include "opencv2/imgproc/imgproc.hpp" 3 | #include "opencv2/highgui/highgui.hpp" 4 | #include "opencv2/gpu/gpu.hpp" 5 | 6 | #include 7 | #include 8 | using namespace cv; 9 | using namespace cv::gpu; 10 | 11 | static void convertFlowToImage(const Mat &flow_x, const Mat &flow_y, Mat &img_x, Mat &img_y, 12 | double lowerBound, double higherBound) { 13 | #define CAST(v, L, H) ((v) > (H) ? 255 : (v) < (L) ? 0 : cvRound(255*((v) - (L))/((H)-(L)))) 14 | for (int i = 0; i < flow_x.rows; ++i) { 15 | for (int j = 0; j < flow_y.cols; ++j) { 16 | float x = flow_x.at(i,j); 17 | float y = flow_y.at(i,j); 18 | img_x.at(i,j) = CAST(x, lowerBound, higherBound); 19 | img_y.at(i,j) = CAST(y, lowerBound, higherBound); 20 | } 21 | } 22 | #undef CAST 23 | } 24 | 25 | static void drawOptFlowMap(const Mat& flow, Mat& cflowmap, int step,double, const Scalar& color){ 26 | for(int y = 0; y < cflowmap.rows; y += step) 27 | for(int x = 0; x < cflowmap.cols; x += step) 28 | { 29 | const Point2f& fxy = flow.at(y, x); 30 | line(cflowmap, Point(x,y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), 31 | color); 32 | circle(cflowmap, Point(x,y), 2, color, -1); 33 | } 34 | } 35 | 36 | int main(int argc, char** argv){ 37 | // IO operation 38 | const char* keys = 39 | { 40 | "{ f | vidFile | ex.avi | filename of video }" 41 | "{ x | xFlowFile | x | filename prefix of flow x component }" 42 | "{ y | yFlowFile | y | filename prefix of flow x component }" 43 | "{ i | imgFile | i | filename prefix of image }" 44 | "{ b | bound | 20 | specify the maximum (px) of optical flow }" 45 | "{ t | type | 1 | specify the optical flow algorithm }" 46 | "{ d | device_id | 0 | specify gpu id }" 47 | "{ s | step | 1 | specify the step for frame sampling }" 48 | "{ h | height | 0 | specify the height of saved flows, 0: keep original height }" 49 | "{ w | width | 0 | specify the width of saved flows, 0: keep original width }" 50 | }; 51 | 52 | CommandLineParser cmd(argc, argv, keys); 53 | string vidFile = cmd.get("vidFile"); 54 | string xFlowFile = cmd.get("xFlowFile"); 55 | string yFlowFile = cmd.get("yFlowFile"); 56 | string imgFile = cmd.get("imgFile"); 57 | int bound = cmd.get("bound"); 58 | int type = cmd.get("type"); 59 | int device_id = cmd.get("device_id"); 60 | int step = cmd.get("step"); 61 | int height = cmd.get("height"); 62 | int width = cmd.get("width"); 63 | 64 | VideoCapture capture(vidFile); 65 | if(!capture.isOpened()) { 66 | printf("Could not initialize capturing..\n"); 67 | return -1; 68 | } 69 | 70 | int frame_num = 0; 71 | Mat image, prev_image, prev_grey, grey, frame, flow_x, flow_y; 72 | GpuMat frame_0, frame_1, flow_u, flow_v; 73 | 74 | setDevice(device_id); 75 | FarnebackOpticalFlow alg_farn; 76 | OpticalFlowDual_TVL1_GPU alg_tvl1; 77 | BroxOpticalFlow alg_brox(0.197f, 50.0f, 0.8f, 10, 77, 10); 78 | 79 | while(true) { 80 | capture >> frame; 81 | if(frame.empty()) 82 | break; 83 | if(frame_num == 0) { 84 | image.create(frame.size(), CV_8UC3); 85 | grey.create(frame.size(), CV_8UC1); 86 | prev_image.create(frame.size(), CV_8UC3); 87 | prev_grey.create(frame.size(), CV_8UC1); 88 | 89 | frame.copyTo(prev_image); 90 | cvtColor(prev_image, prev_grey, CV_BGR2GRAY); 91 | 92 | frame_num++; 93 | 94 | int step_t = step; 95 | while (step_t > 1){ 96 | capture >> frame; 97 | step_t--; 98 | } 99 | continue; 100 | } 101 | 102 | frame.copyTo(image); 103 | cvtColor(image, grey, CV_BGR2GRAY); 104 | 105 | 106 | frame_0.upload(prev_grey); 107 | frame_1.upload(grey); 108 | 109 | 110 | // GPU optical flow 111 | switch(type){ 112 | case 0: 113 | alg_farn(frame_0,frame_1,flow_u,flow_v); 114 | break; 115 | case 1: 116 | alg_tvl1(frame_0,frame_1,flow_u,flow_v); 117 | break; 118 | case 2: 119 | GpuMat d_frame0f, d_frame1f; 120 | frame_0.convertTo(d_frame0f, CV_32F, 1.0 / 255.0); 121 | frame_1.convertTo(d_frame1f, CV_32F, 1.0 / 255.0); 122 | alg_brox(d_frame0f, d_frame1f, flow_u,flow_v); 123 | break; 124 | } 125 | 126 | flow_u.download(flow_x); 127 | flow_v.download(flow_y); 128 | 129 | // Output optical flow 130 | Mat imgX(flow_x.size(),CV_8UC1); 131 | Mat imgY(flow_y.size(),CV_8UC1); 132 | convertFlowToImage(flow_x,flow_y, imgX, imgY, -bound, bound); 133 | char tmp[20]; 134 | sprintf(tmp,"_%06d.jpg",int(frame_num)); 135 | 136 | Mat imgX_, imgY_, image_; 137 | height = (height > 0)? height : imgX.rows; 138 | width = (width > 0)? width : imgX.cols; 139 | resize(imgX,imgX_,cv::Size(width,height)); 140 | resize(imgY,imgY_,cv::Size(width,height)); 141 | resize(image,image_,cv::Size(width,height)); 142 | 143 | imwrite(xFlowFile + tmp,imgX_); 144 | imwrite(yFlowFile + tmp,imgY_); 145 | imwrite(imgFile + tmp, image_); 146 | 147 | std::swap(prev_grey, grey); 148 | std::swap(prev_image, image); 149 | frame_num = frame_num + 1; 150 | 151 | int step_t = step; 152 | while (step_t > 1){ 153 | capture >> frame; 154 | step_t--; 155 | } 156 | } 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /ex.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangwangx/denseFlow_gpu/a3d4d4e893689374637e8ce7cfda7c05be7131a9/ex.avi --------------------------------------------------------------------------------