opencl-opencv-interop.cpp 34 KB

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