Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/opencl/opencl-opencv-interop.cpp
16337 views
1
/*
2
// The example of interoperability between OpenCL and OpenCV.
3
// This will loop through frames of video either from input media file
4
// or camera device and do processing of these data in OpenCL and then
5
// in OpenCV. In OpenCL it does inversion of pixels in left half of frame and
6
// in OpenCV it does bluring in the right half of frame.
7
*/
8
#include <cstdio>
9
#include <cstdlib>
10
#include <iostream>
11
#include <fstream>
12
#include <string>
13
#include <sstream>
14
#include <iomanip>
15
#include <stdexcept>
16
17
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
18
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
19
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS // eliminate build warning
20
21
#ifdef __APPLE__
22
#include <OpenCL/cl.h>
23
#else
24
#include <CL/cl.h>
25
#endif
26
27
#include <opencv2/core/ocl.hpp>
28
#include <opencv2/core/utility.hpp>
29
#include <opencv2/video.hpp>
30
#include <opencv2/highgui.hpp>
31
#include <opencv2/imgproc.hpp>
32
33
34
using namespace std;
35
using namespace cv;
36
37
namespace opencl {
38
39
class PlatformInfo
40
{
41
public:
42
PlatformInfo()
43
{}
44
45
~PlatformInfo()
46
{}
47
48
cl_int QueryInfo(cl_platform_id id)
49
{
50
query_param(id, CL_PLATFORM_PROFILE, m_profile);
51
query_param(id, CL_PLATFORM_VERSION, m_version);
52
query_param(id, CL_PLATFORM_NAME, m_name);
53
query_param(id, CL_PLATFORM_VENDOR, m_vendor);
54
query_param(id, CL_PLATFORM_EXTENSIONS, m_extensions);
55
return CL_SUCCESS;
56
}
57
58
std::string Profile() { return m_profile; }
59
std::string Version() { return m_version; }
60
std::string Name() { return m_name; }
61
std::string Vendor() { return m_vendor; }
62
std::string Extensions() { return m_extensions; }
63
64
private:
65
cl_int query_param(cl_platform_id id, cl_platform_info param, std::string& paramStr)
66
{
67
cl_int res;
68
69
size_t psize;
70
cv::AutoBuffer<char> buf;
71
72
res = clGetPlatformInfo(id, param, 0, 0, &psize);
73
if (CL_SUCCESS != res)
74
throw std::runtime_error(std::string("clGetPlatformInfo failed"));
75
76
buf.resize(psize);
77
res = clGetPlatformInfo(id, param, psize, buf, 0);
78
if (CL_SUCCESS != res)
79
throw std::runtime_error(std::string("clGetPlatformInfo failed"));
80
81
// just in case, ensure trailing zero for ASCIIZ string
82
buf[psize] = 0;
83
84
paramStr = buf;
85
86
return CL_SUCCESS;
87
}
88
89
private:
90
std::string m_profile;
91
std::string m_version;
92
std::string m_name;
93
std::string m_vendor;
94
std::string m_extensions;
95
};
96
97
98
class DeviceInfo
99
{
100
public:
101
DeviceInfo()
102
{}
103
104
~DeviceInfo()
105
{}
106
107
cl_int QueryInfo(cl_device_id id)
108
{
109
query_param(id, CL_DEVICE_TYPE, m_type);
110
query_param(id, CL_DEVICE_VENDOR_ID, m_vendor_id);
111
query_param(id, CL_DEVICE_MAX_COMPUTE_UNITS, m_max_compute_units);
112
query_param(id, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, m_max_work_item_dimensions);
113
query_param(id, CL_DEVICE_MAX_WORK_ITEM_SIZES, m_max_work_item_sizes);
114
query_param(id, CL_DEVICE_MAX_WORK_GROUP_SIZE, m_max_work_group_size);
115
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, m_preferred_vector_width_char);
116
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, m_preferred_vector_width_short);
117
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, m_preferred_vector_width_int);
118
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, m_preferred_vector_width_long);
119
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, m_preferred_vector_width_float);
120
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, m_preferred_vector_width_double);
121
#if defined(CL_VERSION_1_1)
122
query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, m_preferred_vector_width_half);
123
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, m_native_vector_width_char);
124
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, m_native_vector_width_short);
125
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, m_native_vector_width_int);
126
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, m_native_vector_width_long);
127
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, m_native_vector_width_float);
128
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, m_native_vector_width_double);
129
query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, m_native_vector_width_half);
130
#endif
131
query_param(id, CL_DEVICE_MAX_CLOCK_FREQUENCY, m_max_clock_frequency);
132
query_param(id, CL_DEVICE_ADDRESS_BITS, m_address_bits);
133
query_param(id, CL_DEVICE_MAX_MEM_ALLOC_SIZE, m_max_mem_alloc_size);
134
query_param(id, CL_DEVICE_IMAGE_SUPPORT, m_image_support);
135
query_param(id, CL_DEVICE_MAX_READ_IMAGE_ARGS, m_max_read_image_args);
136
query_param(id, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, m_max_write_image_args);
137
#if defined(CL_VERSION_2_0)
138
query_param(id, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, m_max_read_write_image_args);
139
#endif
140
query_param(id, CL_DEVICE_IMAGE2D_MAX_WIDTH, m_image2d_max_width);
141
query_param(id, CL_DEVICE_IMAGE2D_MAX_HEIGHT, m_image2d_max_height);
142
query_param(id, CL_DEVICE_IMAGE3D_MAX_WIDTH, m_image3d_max_width);
143
query_param(id, CL_DEVICE_IMAGE3D_MAX_HEIGHT, m_image3d_max_height);
144
query_param(id, CL_DEVICE_IMAGE3D_MAX_DEPTH, m_image3d_max_depth);
145
#if defined(CL_VERSION_1_2)
146
query_param(id, CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, m_image_max_buffer_size);
147
query_param(id, CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, m_image_max_array_size);
148
#endif
149
query_param(id, CL_DEVICE_MAX_SAMPLERS, m_max_samplers);
150
#if defined(CL_VERSION_1_2)
151
query_param(id, CL_DEVICE_IMAGE_PITCH_ALIGNMENT, m_image_pitch_alignment);
152
query_param(id, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, m_image_base_address_alignment);
153
#endif
154
#if defined(CL_VERSION_2_0)
155
query_param(id, CL_DEVICE_MAX_PIPE_ARGS, m_max_pipe_args);
156
query_param(id, CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS, m_pipe_max_active_reservations);
157
query_param(id, CL_DEVICE_PIPE_MAX_PACKET_SIZE, m_pipe_max_packet_size);
158
#endif
159
query_param(id, CL_DEVICE_MAX_PARAMETER_SIZE, m_max_parameter_size);
160
query_param(id, CL_DEVICE_MEM_BASE_ADDR_ALIGN, m_mem_base_addr_align);
161
query_param(id, CL_DEVICE_SINGLE_FP_CONFIG, m_single_fp_config);
162
#if defined(CL_VERSION_1_2)
163
query_param(id, CL_DEVICE_DOUBLE_FP_CONFIG, m_double_fp_config);
164
#endif
165
query_param(id, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, m_global_mem_cache_type);
166
query_param(id, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, m_global_mem_cacheline_size);
167
query_param(id, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, m_global_mem_cache_size);
168
query_param(id, CL_DEVICE_GLOBAL_MEM_SIZE, m_global_mem_size);
169
query_param(id, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, m_max_constant_buffer_size);
170
query_param(id, CL_DEVICE_MAX_CONSTANT_ARGS, m_max_constant_args);
171
#if defined(CL_VERSION_2_0)
172
query_param(id, CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, m_max_global_variable_size);
173
query_param(id, CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, m_global_variable_preferred_total_size);
174
#endif
175
query_param(id, CL_DEVICE_LOCAL_MEM_TYPE, m_local_mem_type);
176
query_param(id, CL_DEVICE_LOCAL_MEM_SIZE, m_local_mem_size);
177
query_param(id, CL_DEVICE_ERROR_CORRECTION_SUPPORT, m_error_correction_support);
178
#if defined(CL_VERSION_1_1)
179
query_param(id, CL_DEVICE_HOST_UNIFIED_MEMORY, m_host_unified_memory);
180
#endif
181
query_param(id, CL_DEVICE_PROFILING_TIMER_RESOLUTION, m_profiling_timer_resolution);
182
query_param(id, CL_DEVICE_ENDIAN_LITTLE, m_endian_little);
183
query_param(id, CL_DEVICE_AVAILABLE, m_available);
184
query_param(id, CL_DEVICE_COMPILER_AVAILABLE, m_compiler_available);
185
#if defined(CL_VERSION_1_2)
186
query_param(id, CL_DEVICE_LINKER_AVAILABLE, m_linker_available);
187
#endif
188
query_param(id, CL_DEVICE_EXECUTION_CAPABILITIES, m_execution_capabilities);
189
query_param(id, CL_DEVICE_QUEUE_PROPERTIES, m_queue_properties);
190
#if defined(CL_VERSION_2_0)
191
query_param(id, CL_DEVICE_QUEUE_ON_HOST_PROPERTIES, m_queue_on_host_properties);
192
query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, m_queue_on_device_properties);
193
query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE, m_queue_on_device_preferred_size);
194
query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, m_queue_on_device_max_size);
195
query_param(id, CL_DEVICE_MAX_ON_DEVICE_QUEUES, m_max_on_device_queues);
196
query_param(id, CL_DEVICE_MAX_ON_DEVICE_EVENTS, m_max_on_device_events);
197
#endif
198
#if defined(CL_VERSION_1_2)
199
query_param(id, CL_DEVICE_BUILT_IN_KERNELS, m_built_in_kernels);
200
#endif
201
query_param(id, CL_DEVICE_PLATFORM, m_platform);
202
query_param(id, CL_DEVICE_NAME, m_name);
203
query_param(id, CL_DEVICE_VENDOR, m_vendor);
204
query_param(id, CL_DRIVER_VERSION, m_driver_version);
205
query_param(id, CL_DEVICE_PROFILE, m_profile);
206
query_param(id, CL_DEVICE_VERSION, m_version);
207
#if defined(CL_VERSION_1_1)
208
query_param(id, CL_DEVICE_OPENCL_C_VERSION, m_opencl_c_version);
209
#endif
210
query_param(id, CL_DEVICE_EXTENSIONS, m_extensions);
211
#if defined(CL_VERSION_1_2)
212
query_param(id, CL_DEVICE_PRINTF_BUFFER_SIZE, m_printf_buffer_size);
213
query_param(id, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, m_preferred_interop_user_sync);
214
query_param(id, CL_DEVICE_PARENT_DEVICE, m_parent_device);
215
query_param(id, CL_DEVICE_PARTITION_MAX_SUB_DEVICES, m_partition_max_sub_devices);
216
query_param(id, CL_DEVICE_PARTITION_PROPERTIES, m_partition_properties);
217
query_param(id, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, m_partition_affinity_domain);
218
query_param(id, CL_DEVICE_PARTITION_TYPE, m_partition_type);
219
query_param(id, CL_DEVICE_REFERENCE_COUNT, m_reference_count);
220
#endif
221
return CL_SUCCESS;
222
}
223
224
std::string Name() { return m_name; }
225
226
private:
227
template<typename T>
228
cl_int query_param(cl_device_id id, cl_device_info param, T& value)
229
{
230
cl_int res;
231
size_t size = 0;
232
233
res = clGetDeviceInfo(id, param, 0, 0, &size);
234
if (CL_SUCCESS != res && size != 0)
235
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
236
237
if (0 == size)
238
return CL_SUCCESS;
239
240
if (sizeof(T) != size)
241
throw std::runtime_error(std::string("clGetDeviceInfo: param size mismatch"));
242
243
res = clGetDeviceInfo(id, param, size, &value, 0);
244
if (CL_SUCCESS != res)
245
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
246
247
return CL_SUCCESS;
248
}
249
250
template<typename T>
251
cl_int query_param(cl_device_id id, cl_device_info param, std::vector<T>& value)
252
{
253
cl_int res;
254
size_t size;
255
256
res = clGetDeviceInfo(id, param, 0, 0, &size);
257
if (CL_SUCCESS != res)
258
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
259
260
if (0 == size)
261
return CL_SUCCESS;
262
263
value.resize(size / sizeof(T));
264
265
res = clGetDeviceInfo(id, param, size, &value[0], 0);
266
if (CL_SUCCESS != res)
267
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
268
269
return CL_SUCCESS;
270
}
271
272
cl_int query_param(cl_device_id id, cl_device_info param, std::string& value)
273
{
274
cl_int res;
275
size_t size;
276
277
res = clGetDeviceInfo(id, param, 0, 0, &size);
278
if (CL_SUCCESS != res)
279
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
280
281
value.resize(size + 1);
282
283
res = clGetDeviceInfo(id, param, size, &value[0], 0);
284
if (CL_SUCCESS != res)
285
throw std::runtime_error(std::string("clGetDeviceInfo failed"));
286
287
// just in case, ensure trailing zero for ASCIIZ string
288
value[size] = 0;
289
290
return CL_SUCCESS;
291
}
292
293
private:
294
cl_device_type m_type;
295
cl_uint m_vendor_id;
296
cl_uint m_max_compute_units;
297
cl_uint m_max_work_item_dimensions;
298
std::vector<size_t> m_max_work_item_sizes;
299
size_t m_max_work_group_size;
300
cl_uint m_preferred_vector_width_char;
301
cl_uint m_preferred_vector_width_short;
302
cl_uint m_preferred_vector_width_int;
303
cl_uint m_preferred_vector_width_long;
304
cl_uint m_preferred_vector_width_float;
305
cl_uint m_preferred_vector_width_double;
306
#if defined(CL_VERSION_1_1)
307
cl_uint m_preferred_vector_width_half;
308
cl_uint m_native_vector_width_char;
309
cl_uint m_native_vector_width_short;
310
cl_uint m_native_vector_width_int;
311
cl_uint m_native_vector_width_long;
312
cl_uint m_native_vector_width_float;
313
cl_uint m_native_vector_width_double;
314
cl_uint m_native_vector_width_half;
315
#endif
316
cl_uint m_max_clock_frequency;
317
cl_uint m_address_bits;
318
cl_ulong m_max_mem_alloc_size;
319
cl_bool m_image_support;
320
cl_uint m_max_read_image_args;
321
cl_uint m_max_write_image_args;
322
#if defined(CL_VERSION_2_0)
323
cl_uint m_max_read_write_image_args;
324
#endif
325
size_t m_image2d_max_width;
326
size_t m_image2d_max_height;
327
size_t m_image3d_max_width;
328
size_t m_image3d_max_height;
329
size_t m_image3d_max_depth;
330
#if defined(CL_VERSION_1_2)
331
size_t m_image_max_buffer_size;
332
size_t m_image_max_array_size;
333
#endif
334
cl_uint m_max_samplers;
335
#if defined(CL_VERSION_1_2)
336
cl_uint m_image_pitch_alignment;
337
cl_uint m_image_base_address_alignment;
338
#endif
339
#if defined(CL_VERSION_2_0)
340
cl_uint m_max_pipe_args;
341
cl_uint m_pipe_max_active_reservations;
342
cl_uint m_pipe_max_packet_size;
343
#endif
344
size_t m_max_parameter_size;
345
cl_uint m_mem_base_addr_align;
346
cl_device_fp_config m_single_fp_config;
347
#if defined(CL_VERSION_1_2)
348
cl_device_fp_config m_double_fp_config;
349
#endif
350
cl_device_mem_cache_type m_global_mem_cache_type;
351
cl_uint m_global_mem_cacheline_size;
352
cl_ulong m_global_mem_cache_size;
353
cl_ulong m_global_mem_size;
354
cl_ulong m_max_constant_buffer_size;
355
cl_uint m_max_constant_args;
356
#if defined(CL_VERSION_2_0)
357
size_t m_max_global_variable_size;
358
size_t m_global_variable_preferred_total_size;
359
#endif
360
cl_device_local_mem_type m_local_mem_type;
361
cl_ulong m_local_mem_size;
362
cl_bool m_error_correction_support;
363
#if defined(CL_VERSION_1_1)
364
cl_bool m_host_unified_memory;
365
#endif
366
size_t m_profiling_timer_resolution;
367
cl_bool m_endian_little;
368
cl_bool m_available;
369
cl_bool m_compiler_available;
370
#if defined(CL_VERSION_1_2)
371
cl_bool m_linker_available;
372
#endif
373
cl_device_exec_capabilities m_execution_capabilities;
374
cl_command_queue_properties m_queue_properties;
375
#if defined(CL_VERSION_2_0)
376
cl_command_queue_properties m_queue_on_host_properties;
377
cl_command_queue_properties m_queue_on_device_properties;
378
cl_uint m_queue_on_device_preferred_size;
379
cl_uint m_queue_on_device_max_size;
380
cl_uint m_max_on_device_queues;
381
cl_uint m_max_on_device_events;
382
#endif
383
#if defined(CL_VERSION_1_2)
384
std::string m_built_in_kernels;
385
#endif
386
cl_platform_id m_platform;
387
std::string m_name;
388
std::string m_vendor;
389
std::string m_driver_version;
390
std::string m_profile;
391
std::string m_version;
392
#if defined(CL_VERSION_1_1)
393
std::string m_opencl_c_version;
394
#endif
395
std::string m_extensions;
396
#if defined(CL_VERSION_1_2)
397
size_t m_printf_buffer_size;
398
cl_bool m_preferred_interop_user_sync;
399
cl_device_id m_parent_device;
400
cl_uint m_partition_max_sub_devices;
401
std::vector<cl_device_partition_property> m_partition_properties;
402
cl_device_affinity_domain m_partition_affinity_domain;
403
std::vector<cl_device_partition_property> m_partition_type;
404
cl_uint m_reference_count;
405
#endif
406
};
407
408
} // namespace opencl
409
410
411
class App
412
{
413
public:
414
App(CommandLineParser& cmd);
415
~App();
416
417
int initOpenCL();
418
int initVideoSource();
419
420
int process_frame_with_open_cl(cv::Mat& frame, bool use_buffer, cl_mem* cl_buffer);
421
int process_cl_buffer_with_opencv(cl_mem buffer, size_t step, int rows, int cols, int type, cv::UMat& u);
422
int process_cl_image_with_opencv(cl_mem image, cv::UMat& u);
423
424
int run();
425
426
bool isRunning() { return m_running; }
427
bool doProcess() { return m_process; }
428
bool useBuffer() { return m_use_buffer; }
429
430
void setRunning(bool running) { m_running = running; }
431
void setDoProcess(bool process) { m_process = process; }
432
void setUseBuffer(bool use_buffer) { m_use_buffer = use_buffer; }
433
434
protected:
435
bool nextFrame(cv::Mat& frame) { return m_cap.read(frame); }
436
void handleKey(char key);
437
void timerStart();
438
void timerEnd();
439
std::string timeStr() const;
440
std::string message() const;
441
442
private:
443
bool m_running;
444
bool m_process;
445
bool m_use_buffer;
446
447
int64 m_t0;
448
int64 m_t1;
449
float m_time;
450
float m_frequency;
451
452
string m_file_name;
453
int m_camera_id;
454
cv::VideoCapture m_cap;
455
cv::Mat m_frame;
456
cv::Mat m_frameGray;
457
458
opencl::PlatformInfo m_platformInfo;
459
opencl::DeviceInfo m_deviceInfo;
460
std::vector<cl_platform_id> m_platform_ids;
461
cl_context m_context;
462
cl_device_id m_device_id;
463
cl_command_queue m_queue;
464
cl_program m_program;
465
cl_kernel m_kernelBuf;
466
cl_kernel m_kernelImg;
467
cl_mem m_img_src; // used as src in case processing of cl image
468
cl_mem m_mem_obj;
469
cl_event m_event;
470
};
471
472
473
App::App(CommandLineParser& cmd)
474
{
475
cout << "\nPress ESC to exit\n" << endl;
476
cout << "\n 'p' to toggle ON/OFF processing\n" << endl;
477
cout << "\n SPACE to switch between OpenCL buffer/image\n" << endl;
478
479
m_camera_id = cmd.get<int>("camera");
480
m_file_name = cmd.get<string>("video");
481
482
m_running = false;
483
m_process = false;
484
m_use_buffer = false;
485
486
m_t0 = 0;
487
m_t1 = 0;
488
m_time = 0.0;
489
m_frequency = (float)cv::getTickFrequency();
490
491
m_context = 0;
492
m_device_id = 0;
493
m_queue = 0;
494
m_program = 0;
495
m_kernelBuf = 0;
496
m_kernelImg = 0;
497
m_img_src = 0;
498
m_mem_obj = 0;
499
m_event = 0;
500
} // ctor
501
502
503
App::~App()
504
{
505
if (m_queue)
506
{
507
clFinish(m_queue);
508
clReleaseCommandQueue(m_queue);
509
m_queue = 0;
510
}
511
512
if (m_program)
513
{
514
clReleaseProgram(m_program);
515
m_program = 0;
516
}
517
518
if (m_img_src)
519
{
520
clReleaseMemObject(m_img_src);
521
m_img_src = 0;
522
}
523
524
if (m_mem_obj)
525
{
526
clReleaseMemObject(m_mem_obj);
527
m_mem_obj = 0;
528
}
529
530
if (m_event)
531
{
532
clReleaseEvent(m_event);
533
}
534
535
if (m_kernelBuf)
536
{
537
clReleaseKernel(m_kernelBuf);
538
m_kernelBuf = 0;
539
}
540
541
if (m_kernelImg)
542
{
543
clReleaseKernel(m_kernelImg);
544
m_kernelImg = 0;
545
}
546
547
if (m_device_id)
548
{
549
clReleaseDevice(m_device_id);
550
m_device_id = 0;
551
}
552
553
if (m_context)
554
{
555
clReleaseContext(m_context);
556
m_context = 0;
557
}
558
} // dtor
559
560
561
int App::initOpenCL()
562
{
563
cl_int res = CL_SUCCESS;
564
cl_uint num_entries = 0;
565
566
res = clGetPlatformIDs(0, 0, &num_entries);
567
if (CL_SUCCESS != res)
568
return -1;
569
570
m_platform_ids.resize(num_entries);
571
572
res = clGetPlatformIDs(num_entries, &m_platform_ids[0], 0);
573
if (CL_SUCCESS != res)
574
return -1;
575
576
unsigned int i;
577
578
// create context from first platform with GPU device
579
for (i = 0; i < m_platform_ids.size(); i++)
580
{
581
cl_context_properties props[] =
582
{
583
CL_CONTEXT_PLATFORM,
584
(cl_context_properties)(m_platform_ids[i]),
585
0
586
};
587
588
m_context = clCreateContextFromType(props, CL_DEVICE_TYPE_GPU, 0, 0, &res);
589
if (0 == m_context || CL_SUCCESS != res)
590
continue;
591
592
res = clGetContextInfo(m_context, CL_CONTEXT_DEVICES, sizeof(cl_device_id), &m_device_id, 0);
593
if (CL_SUCCESS != res)
594
return -1;
595
596
m_queue = clCreateCommandQueue(m_context, m_device_id, 0, &res);
597
if (0 == m_queue || CL_SUCCESS != res)
598
return -1;
599
600
const char* kernelSrc =
601
"__kernel "
602
"void bitwise_inv_buf_8uC1("
603
" __global unsigned char* pSrcDst,"
604
" int srcDstStep,"
605
" int rows,"
606
" int cols)"
607
"{"
608
" int x = get_global_id(0);"
609
" int y = get_global_id(1);"
610
" int idx = mad24(y, srcDstStep, x);"
611
" pSrcDst[idx] = ~pSrcDst[idx];"
612
"}"
613
"__kernel "
614
"void bitwise_inv_img_8uC1("
615
" read_only image2d_t srcImg,"
616
" write_only image2d_t dstImg)"
617
"{"
618
" int x = get_global_id(0);"
619
" int y = get_global_id(1);"
620
" int2 coord = (int2)(x, y);"
621
" uint4 val = read_imageui(srcImg, coord);"
622
" val.x = (~val.x) & 0x000000FF;"
623
" write_imageui(dstImg, coord, val);"
624
"}";
625
size_t len = strlen(kernelSrc);
626
m_program = clCreateProgramWithSource(m_context, 1, &kernelSrc, &len, &res);
627
if (0 == m_program || CL_SUCCESS != res)
628
return -1;
629
630
res = clBuildProgram(m_program, 1, &m_device_id, 0, 0, 0);
631
if (CL_SUCCESS != res)
632
return -1;
633
634
m_kernelBuf = clCreateKernel(m_program, "bitwise_inv_buf_8uC1", &res);
635
if (0 == m_kernelBuf || CL_SUCCESS != res)
636
return -1;
637
638
m_kernelImg = clCreateKernel(m_program, "bitwise_inv_img_8uC1", &res);
639
if (0 == m_kernelImg || CL_SUCCESS != res)
640
return -1;
641
642
m_platformInfo.QueryInfo(m_platform_ids[i]);
643
m_deviceInfo.QueryInfo(m_device_id);
644
645
// attach OpenCL context to OpenCV
646
cv::ocl::attachContext(m_platformInfo.Name(), m_platform_ids[i], m_context, m_device_id);
647
648
break;
649
}
650
651
return m_context != 0 ? CL_SUCCESS : -1;
652
} // initOpenCL()
653
654
655
int App::initVideoSource()
656
{
657
try
658
{
659
if (!m_file_name.empty() && m_camera_id == -1)
660
{
661
m_cap.open(m_file_name.c_str());
662
if (!m_cap.isOpened())
663
throw std::runtime_error(std::string("can't open video file: " + m_file_name));
664
}
665
else if (m_camera_id != -1)
666
{
667
m_cap.open(m_camera_id);
668
if (!m_cap.isOpened())
669
{
670
std::stringstream msg;
671
msg << "can't open camera: " << m_camera_id;
672
throw std::runtime_error(msg.str());
673
}
674
}
675
else
676
throw std::runtime_error(std::string("specify video source"));
677
}
678
679
catch (std::exception e)
680
{
681
cerr << "ERROR: " << e.what() << std::endl;
682
return -1;
683
}
684
685
return 0;
686
} // initVideoSource()
687
688
689
// this function is an example of "typical" OpenCL processing pipeline
690
// It creates OpenCL buffer or image, depending on use_buffer flag,
691
// from input media frame and process these data
692
// (inverts each pixel value in half of frame) with OpenCL kernel
693
int App::process_frame_with_open_cl(cv::Mat& frame, bool use_buffer, cl_mem* mem_obj)
694
{
695
cl_int res = CL_SUCCESS;
696
697
CV_Assert(mem_obj);
698
699
cl_kernel kernel = 0;
700
cl_mem mem = mem_obj[0];
701
702
if (0 == mem || 0 == m_img_src)
703
{
704
// allocate/delete cl memory objects every frame for the simplicity.
705
// in real applicaton more efficient pipeline can be built.
706
707
if (use_buffer)
708
{
709
cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR;
710
711
mem = clCreateBuffer(m_context, flags, frame.total(), frame.ptr(), &res);
712
if (0 == mem || CL_SUCCESS != res)
713
return -1;
714
715
res = clSetKernelArg(m_kernelBuf, 0, sizeof(cl_mem), &mem);
716
if (CL_SUCCESS != res)
717
return -1;
718
719
res = clSetKernelArg(m_kernelBuf, 1, sizeof(int), &frame.step[0]);
720
if (CL_SUCCESS != res)
721
return -1;
722
723
res = clSetKernelArg(m_kernelBuf, 2, sizeof(int), &frame.rows);
724
if (CL_SUCCESS != res)
725
return -1;
726
727
int cols2 = frame.cols / 2;
728
res = clSetKernelArg(m_kernelBuf, 3, sizeof(int), &cols2);
729
if (CL_SUCCESS != res)
730
return -1;
731
732
kernel = m_kernelBuf;
733
}
734
else
735
{
736
cl_mem_flags flags_src = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;
737
738
cl_image_format fmt;
739
fmt.image_channel_order = CL_R;
740
fmt.image_channel_data_type = CL_UNSIGNED_INT8;
741
742
cl_image_desc desc_src;
743
desc_src.image_type = CL_MEM_OBJECT_IMAGE2D;
744
desc_src.image_width = frame.cols;
745
desc_src.image_height = frame.rows;
746
desc_src.image_depth = 0;
747
desc_src.image_array_size = 0;
748
desc_src.image_row_pitch = frame.step[0];
749
desc_src.image_slice_pitch = 0;
750
desc_src.num_mip_levels = 0;
751
desc_src.num_samples = 0;
752
desc_src.buffer = 0;
753
m_img_src = clCreateImage(m_context, flags_src, &fmt, &desc_src, frame.ptr(), &res);
754
if (0 == m_img_src || CL_SUCCESS != res)
755
return -1;
756
757
cl_mem_flags flags_dst = CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR;
758
759
cl_image_desc desc_dst;
760
desc_dst.image_type = CL_MEM_OBJECT_IMAGE2D;
761
desc_dst.image_width = frame.cols;
762
desc_dst.image_height = frame.rows;
763
desc_dst.image_depth = 0;
764
desc_dst.image_array_size = 0;
765
desc_dst.image_row_pitch = 0;
766
desc_dst.image_slice_pitch = 0;
767
desc_dst.num_mip_levels = 0;
768
desc_dst.num_samples = 0;
769
desc_dst.buffer = 0;
770
mem = clCreateImage(m_context, flags_dst, &fmt, &desc_dst, 0, &res);
771
if (0 == mem || CL_SUCCESS != res)
772
return -1;
773
774
size_t origin[] = { 0, 0, 0 };
775
size_t region[] = { (size_t)frame.cols, (size_t)frame.rows, 1 };
776
res = clEnqueueCopyImage(m_queue, m_img_src, mem, origin, origin, region, 0, 0, &m_event);
777
if (CL_SUCCESS != res)
778
return -1;
779
780
res = clWaitForEvents(1, &m_event);
781
if (CL_SUCCESS != res)
782
return -1;
783
784
res = clSetKernelArg(m_kernelImg, 0, sizeof(cl_mem), &m_img_src);
785
if (CL_SUCCESS != res)
786
return -1;
787
788
res = clSetKernelArg(m_kernelImg, 1, sizeof(cl_mem), &mem);
789
if (CL_SUCCESS != res)
790
return -1;
791
792
kernel = m_kernelImg;
793
}
794
}
795
796
m_event = clCreateUserEvent(m_context, &res);
797
if (0 == m_event || CL_SUCCESS != res)
798
return -1;
799
800
// process left half of frame in OpenCL
801
size_t size[] = { (size_t)frame.cols / 2, (size_t)frame.rows };
802
res = clEnqueueNDRangeKernel(m_queue, kernel, 2, 0, size, 0, 0, 0, &m_event);
803
if (CL_SUCCESS != res)
804
return -1;
805
806
res = clWaitForEvents(1, &m_event);
807
if (CL_SUCCESS != res)
808
return - 1;
809
810
mem_obj[0] = mem;
811
812
return 0;
813
}
814
815
816
// this function is an example of interoperability between OpenCL buffer
817
// and OpenCV UMat objects. It converts (without copying data) OpenCL buffer
818
// to OpenCV UMat and then do blur on these data
819
int App::process_cl_buffer_with_opencv(cl_mem buffer, size_t step, int rows, int cols, int type, cv::UMat& u)
820
{
821
cv::ocl::convertFromBuffer(buffer, step, rows, cols, type, u);
822
823
// process right half of frame in OpenCV
824
cv::Point pt(u.cols / 2, 0);
825
cv::Size sz(u.cols / 2, u.rows);
826
cv::Rect roi(pt, sz);
827
cv::UMat uroi(u, roi);
828
cv::blur(uroi, uroi, cv::Size(7, 7), cv::Point(-3, -3));
829
830
if (buffer)
831
clReleaseMemObject(buffer);
832
m_mem_obj = 0;
833
834
return 0;
835
}
836
837
838
// this function is an example of interoperability between OpenCL image
839
// and OpenCV UMat objects. It converts OpenCL image
840
// to OpenCV UMat and then do blur on these data
841
int App::process_cl_image_with_opencv(cl_mem image, cv::UMat& u)
842
{
843
cv::ocl::convertFromImage(image, u);
844
845
// process right half of frame in OpenCV
846
cv::Point pt(u.cols / 2, 0);
847
cv::Size sz(u.cols / 2, u.rows);
848
cv::Rect roi(pt, sz);
849
cv::UMat uroi(u, roi);
850
cv::blur(uroi, uroi, cv::Size(7, 7), cv::Point(-3, -3));
851
852
if (image)
853
clReleaseMemObject(image);
854
m_mem_obj = 0;
855
856
if (m_img_src)
857
clReleaseMemObject(m_img_src);
858
m_img_src = 0;
859
860
return 0;
861
}
862
863
864
int App::run()
865
{
866
if (0 != initOpenCL())
867
return -1;
868
869
if (0 != initVideoSource())
870
return -1;
871
872
Mat img_to_show;
873
874
// set running state until ESC pressed
875
setRunning(true);
876
// set process flag to show some data processing
877
// can be toggled on/off by 'p' button
878
setDoProcess(true);
879
// set use buffer flag,
880
// when it is set to true, will demo interop opencl buffer and cv::Umat,
881
// otherwise demo interop opencl image and cv::UMat
882
// can be switched on/of by SPACE button
883
setUseBuffer(true);
884
885
// Iterate over all frames
886
while (isRunning() && nextFrame(m_frame))
887
{
888
cv::cvtColor(m_frame, m_frameGray, COLOR_BGR2GRAY);
889
890
UMat uframe;
891
892
// work
893
timerStart();
894
895
if (doProcess())
896
{
897
process_frame_with_open_cl(m_frameGray, useBuffer(), &m_mem_obj);
898
899
if (useBuffer())
900
process_cl_buffer_with_opencv(
901
m_mem_obj, m_frameGray.step[0], m_frameGray.rows, m_frameGray.cols, m_frameGray.type(), uframe);
902
else
903
process_cl_image_with_opencv(m_mem_obj, uframe);
904
}
905
else
906
{
907
m_frameGray.copyTo(uframe);
908
}
909
910
timerEnd();
911
912
uframe.copyTo(img_to_show);
913
914
putText(img_to_show, "Version : " + m_platformInfo.Version(), Point(5, 30), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
915
putText(img_to_show, "Name : " + m_platformInfo.Name(), Point(5, 60), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
916
putText(img_to_show, "Device : " + m_deviceInfo.Name(), Point(5, 90), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
917
cv::String memtype = useBuffer() ? "buffer" : "image";
918
putText(img_to_show, "interop with OpenCL " + memtype, Point(5, 120), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
919
putText(img_to_show, "Time : " + timeStr() + " msec", Point(5, 150), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
920
921
imshow("opencl_interop", img_to_show);
922
923
handleKey((char)waitKey(3));
924
}
925
926
return 0;
927
}
928
929
930
void App::handleKey(char key)
931
{
932
switch (key)
933
{
934
case 27:
935
setRunning(false);
936
break;
937
938
case ' ':
939
setUseBuffer(!useBuffer());
940
break;
941
942
case 'p':
943
case 'P':
944
setDoProcess( !doProcess() );
945
break;
946
947
default:
948
break;
949
}
950
}
951
952
953
inline void App::timerStart()
954
{
955
m_t0 = getTickCount();
956
}
957
958
959
inline void App::timerEnd()
960
{
961
m_t1 = getTickCount();
962
int64 delta = m_t1 - m_t0;
963
m_time = (delta / m_frequency) * 1000; // units msec
964
}
965
966
967
inline string App::timeStr() const
968
{
969
stringstream ss;
970
ss << std::fixed << std::setprecision(1) << m_time;
971
return ss.str();
972
}
973
974
975
int main(int argc, char** argv)
976
{
977
const char* keys =
978
"{ help h ? | | print help message }"
979
"{ camera c | -1 | use camera as input }"
980
"{ video v | | use video as input }";
981
982
CommandLineParser cmd(argc, argv, keys);
983
if (cmd.has("help"))
984
{
985
cmd.printMessage();
986
return EXIT_SUCCESS;
987
}
988
989
App app(cmd);
990
991
try
992
{
993
app.run();
994
}
995
996
catch (const cv::Exception& e)
997
{
998
cout << "error: " << e.what() << endl;
999
return 1;
1000
}
1001
1002
catch (const std::exception& e)
1003
{
1004
cout << "error: " << e.what() << endl;
1005
return 1;
1006
}
1007
1008
catch (...)
1009
{
1010
cout << "unknown exception" << endl;
1011
return 1;
1012
}
1013
1014
return EXIT_SUCCESS;
1015
} // main()
1016
1017