Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hackassin
GitHub Repository: hackassin/learnopencv
Path: blob/master/Getting-Started-OpenCV-CUDA-Module/demo.cpp
3119 views
1
#include <iostream>
2
#include <string>
3
#include <vector>
4
#include <unordered_map>
5
#include <stdlib.h>
6
#include <chrono>
7
8
#include <opencv2/core.hpp>
9
#include <opencv2/imgproc.hpp>
10
#include <opencv2/highgui.hpp>
11
#include <opencv2/videoio.hpp>
12
#include <opencv2/video.hpp>
13
#include <opencv2/cudaarithm.hpp>
14
#include <opencv2/cudaimgproc.hpp>
15
#include <opencv2/cudawarping.hpp>
16
#include <opencv2/cudaoptflow.hpp>
17
18
using namespace cv;
19
using namespace cv::cuda;
20
using namespace std;
21
using namespace std::chrono;
22
23
24
void calculate_optical_flow(string videoFileName, string device)
25
{
26
// init map to track time for every stage at each iteration
27
unordered_map<string, vector<double>> timers;
28
29
// init video capture with video
30
VideoCapture capture(videoFileName);
31
if (!capture.isOpened())
32
{
33
// error in opening the video file
34
cout << "Unable to open file!" << endl;
35
return;
36
}
37
38
// get default video FPS
39
double fps = capture.get(CAP_PROP_FPS);
40
41
// get total number of video frames
42
int num_frames = int(capture.get(CAP_PROP_FRAME_COUNT));
43
44
// read the first frame
45
cv::Mat frame, previous_frame;
46
capture >> frame;
47
48
if (device == "cpu")
49
{
50
// resize frame
51
cv::resize(frame, frame, Size(960, 540), 0, 0, INTER_LINEAR);
52
53
// convert to gray
54
cv::cvtColor(frame, previous_frame, COLOR_BGR2GRAY);
55
56
// declare outputs for optical flow
57
cv::Mat magnitude, normalized_magnitude, angle;
58
cv::Mat hsv[3], merged_hsv, hsv_8u, bgr;
59
60
// set saturation to 1
61
hsv[1] = cv::Mat::ones(frame.size(), CV_32F);
62
63
while (true)
64
{
65
// start full pipeline timer
66
auto start_full_time = high_resolution_clock::now();
67
68
// start reading timer
69
auto start_read_time = high_resolution_clock::now();
70
71
// capture frame-by-frame
72
capture >> frame;
73
74
if (frame.empty())
75
break;
76
77
// end reading timer
78
auto end_read_time = high_resolution_clock::now();
79
80
// add elapsed iteration time
81
timers["reading"].push_back(duration_cast<milliseconds>(end_read_time - start_read_time).count() / 1000.0);
82
83
// start pre-process timer
84
auto start_pre_time = high_resolution_clock::now();
85
86
// resize frame
87
cv::resize(frame, frame, Size(960, 540), 0, 0, INTER_LINEAR);
88
89
// convert to gray
90
cv::Mat current_frame;
91
cv::cvtColor(frame, current_frame, COLOR_BGR2GRAY);
92
93
// end pre-process timer
94
auto end_pre_time = high_resolution_clock::now();
95
96
// add elapsed iteration time
97
timers["pre-process"].push_back(duration_cast<milliseconds>(end_pre_time - start_pre_time).count() / 1000.0);
98
99
// start optical flow timer
100
auto start_of_time = high_resolution_clock::now();
101
102
// calculate optical flow
103
cv::Mat flow;
104
calcOpticalFlowFarneback(previous_frame, current_frame, flow, 0.5, 5, 15, 3, 5, 1.2, 0);
105
106
// end optical flow timer
107
auto end_of_time = high_resolution_clock::now();
108
109
// add elapsed iteration time
110
timers["optical flow"].push_back(duration_cast<milliseconds>(end_of_time - start_of_time).count() / 1000.0);
111
112
// start post-process timer
113
auto start_post_time = high_resolution_clock::now();
114
115
// split the output flow into 2 vectors
116
cv::Mat flow_xy[2], flow_x, flow_y;
117
split(flow, flow_xy);
118
119
// get the result
120
flow_x = flow_xy[0];
121
flow_y = flow_xy[1];
122
123
// convert from cartesian to polar coordinates
124
cv::cartToPolar(flow_x, flow_y, magnitude, angle, true);
125
126
// normalize magnitude from 0 to 1
127
cv::normalize(magnitude, normalized_magnitude, 0.0, 1.0, NORM_MINMAX);
128
129
// get angle of optical flow
130
angle *= ((1 / 360.0) * (180 / 255.0));
131
132
// build hsv image
133
hsv[0] = angle;
134
hsv[2] = normalized_magnitude;
135
merge(hsv, 3, merged_hsv);
136
137
// multiply each pixel value to 255
138
merged_hsv.convertTo(hsv_8u, CV_8U, 255);
139
140
// convert hsv to bgr
141
cv::cvtColor(hsv_8u, bgr, COLOR_HSV2BGR);
142
143
// update previous_frame value
144
previous_frame = current_frame;
145
146
// end post pipeline timer
147
auto end_post_time = high_resolution_clock::now();
148
149
// add elapsed iteration time
150
timers["post-process"].push_back(duration_cast<milliseconds>(end_post_time - start_post_time).count() / 1000.0);
151
152
// end full pipeline timer
153
auto end_full_time = high_resolution_clock::now();
154
155
// add elapsed iteration time
156
timers["full pipeline"].push_back(duration_cast<milliseconds>(end_full_time - start_full_time).count() / 1000.0);
157
158
// visualization
159
imshow("original", frame);
160
imshow("result", bgr);
161
int keyboard = waitKey(1);
162
if (keyboard == 27)
163
break;
164
}
165
}
166
else
167
{
168
// resize frame
169
cv::resize(frame, frame, Size(960, 540), 0, 0, INTER_LINEAR);
170
171
// convert to gray
172
cv::cvtColor(frame, previous_frame, COLOR_BGR2GRAY);
173
174
// upload pre-processed frame to GPU
175
cv::cuda::GpuMat gpu_previous;
176
gpu_previous.upload(previous_frame);
177
178
// declare cpu outputs for optical flow
179
cv::Mat hsv[3], angle, bgr;
180
181
// declare gpu outputs for optical flow
182
cv::cuda::GpuMat gpu_magnitude, gpu_normalized_magnitude, gpu_angle;
183
cv::cuda::GpuMat gpu_hsv[3], gpu_merged_hsv, gpu_hsv_8u, gpu_bgr;
184
185
// set saturation to 1
186
hsv[1] = cv::Mat::ones(frame.size(), CV_32F);
187
gpu_hsv[1].upload(hsv[1]);
188
189
while (true)
190
{
191
// start full pipeline timer
192
auto start_full_time = high_resolution_clock::now();
193
194
// start reading timer
195
auto start_read_time = high_resolution_clock::now();
196
197
// capture frame-by-frame
198
capture >> frame;
199
200
if (frame.empty())
201
break;
202
203
// upload frame to GPU
204
cv::cuda::GpuMat gpu_frame;
205
gpu_frame.upload(frame);
206
207
// end reading timer
208
auto end_read_time = high_resolution_clock::now();
209
210
// add elapsed iteration time
211
timers["reading"].push_back(duration_cast<milliseconds>(end_read_time - start_read_time).count() / 1000.0);
212
213
// start pre-process timer
214
auto start_pre_time = high_resolution_clock::now();
215
216
// resize frame
217
cv::cuda::resize(gpu_frame, gpu_frame, Size(960, 540), 0, 0, INTER_LINEAR);
218
219
// convert to gray
220
cv::cuda::GpuMat gpu_current;
221
cv::cuda::cvtColor(gpu_frame, gpu_current, COLOR_BGR2GRAY);
222
223
// end pre-process timer
224
auto end_pre_time = high_resolution_clock::now();
225
226
// add elapsed iteration time
227
timers["pre-process"].push_back(duration_cast<milliseconds>(end_pre_time - start_pre_time).count() / 1000.0);
228
229
// start optical flow timer
230
auto start_of_time = high_resolution_clock::now();
231
232
// create optical flow instance
233
Ptr<cuda::FarnebackOpticalFlow> ptr_calc = cuda::FarnebackOpticalFlow::create(5, 0.5, false, 15, 3, 5, 1.2, 0);
234
// calculate optical flow
235
cv::cuda::GpuMat gpu_flow;
236
ptr_calc->calc(gpu_previous, gpu_current, gpu_flow);
237
238
// end optical flow timer
239
auto end_of_time = high_resolution_clock::now();
240
241
// add elapsed iteration time
242
timers["optical flow"].push_back(duration_cast<milliseconds>(end_of_time - start_of_time).count() / 1000.0);
243
244
// start post-process timer
245
auto start_post_time = high_resolution_clock::now();
246
247
// split the output flow into 2 vectors
248
cv::cuda::GpuMat gpu_flow_xy[2];
249
cv::cuda::split(gpu_flow, gpu_flow_xy);
250
251
// convert from cartesian to polar coordinates
252
cv::cuda::cartToPolar(gpu_flow_xy[0], gpu_flow_xy[1], gpu_magnitude, gpu_angle, true);
253
254
// normalize magnitude from 0 to 1
255
cv::cuda::normalize(gpu_magnitude, gpu_normalized_magnitude, 0.0, 1.0, NORM_MINMAX, -1);
256
257
// get angle of optical flow
258
gpu_angle.download(angle);
259
angle *= ((1 / 360.0) * (180 / 255.0));
260
261
// build hsv image
262
gpu_hsv[0].upload(angle);
263
gpu_hsv[2] = gpu_normalized_magnitude;
264
cv::cuda::merge(gpu_hsv, 3, gpu_merged_hsv);
265
266
// multiply each pixel value to 255
267
gpu_merged_hsv.cv::cuda::GpuMat::convertTo(gpu_hsv_8u, CV_8U, 255.0);
268
269
// convert hsv to bgr
270
cv::cuda::cvtColor(gpu_hsv_8u, gpu_bgr, COLOR_HSV2BGR);
271
272
// send original frame from GPU back to CPU
273
gpu_frame.download(frame);
274
275
// send result from GPU back to CPU
276
gpu_bgr.download(bgr);
277
278
// update previous_frame value
279
gpu_previous = gpu_current;
280
281
// end post pipeline timer
282
auto end_post_time = high_resolution_clock::now();
283
284
// add elapsed iteration time
285
timers["post-process"].push_back(duration_cast<milliseconds>(end_post_time - start_post_time).count() / 1000.0);
286
287
// end full pipeline timer
288
auto end_full_time = high_resolution_clock::now();
289
290
// add elapsed iteration time
291
timers["full pipeline"].push_back(duration_cast<milliseconds>(end_full_time - start_full_time).count() / 1000.0);
292
293
// visualization
294
imshow("original", frame);
295
imshow("result", bgr);
296
int keyboard = waitKey(1);
297
if (keyboard == 27)
298
break;
299
}
300
301
}
302
303
// release the capture
304
capture.release();
305
306
// destroy all windows
307
destroyAllWindows();
308
309
// print results
310
cout << "Number of frames: " << num_frames << std::endl;
311
312
// elapsed time at each stage
313
cout << "Elapsed time" << std::endl;
314
for (auto const& timer : timers)
315
{
316
cout << "- " << timer.first << " : " << accumulate(timer.second.begin(), timer.second.end(), 0.0) << " seconds"<< endl;
317
}
318
319
// calculate frames per second
320
cout << "Default video FPS : " << fps << endl;
321
float optical_flow_fps = (num_frames - 1) / accumulate(timers["optical flow"].begin(), timers["optical flow"].end(), 0.0);
322
cout << "Optical flow FPS : " << optical_flow_fps << endl;
323
324
float full_pipeline_fps = (num_frames - 1) / accumulate(timers["full pipeline"].begin(), timers["full pipeline"].end(), 0.0);
325
cout << "Full pipeline FPS : " << full_pipeline_fps << endl;
326
}
327
328
329
int main( int argc, const char** argv )
330
{
331
string videoFileName;
332
string device;
333
334
// parse arguments from command line
335
if (argc == 3)
336
{
337
videoFileName = argv[1];
338
device = argv[2];
339
}
340
else if (argc == 2)
341
{
342
videoFileName = argv[1];
343
device = "cpu";
344
}
345
else
346
{
347
cout << "Please input video filename." << endl;
348
cout << "Usage example: ./demo.out video/boat.mp4" << endl;
349
cout << "If you want to use GPU device instead of CPU, add one more argument." << endl;
350
cout << "Usage example: ./demo.out video/boat.mp4 gpu" << endl;
351
return 1;
352
}
353
354
// output passed arguments
355
cout << "Configuration" << endl;
356
cout << "- device : "<< device << endl;
357
cout << "- video file : " << videoFileName << endl;
358
359
calculate_optical_flow(videoFileName, device);
360
361
return 0;
362
}
363
364
365