Path: blob/master/samples/opencl/opencl-opencv-interop.cpp
16337 views
/*1// The example of interoperability between OpenCL and OpenCV.2// This will loop through frames of video either from input media file3// or camera device and do processing of these data in OpenCL and then4// in OpenCV. In OpenCL it does inversion of pixels in left half of frame and5// in OpenCV it does bluring in the right half of frame.6*/7#include <cstdio>8#include <cstdlib>9#include <iostream>10#include <fstream>11#include <string>12#include <sstream>13#include <iomanip>14#include <stdexcept>1516#define CL_USE_DEPRECATED_OPENCL_1_1_APIS17#define CL_USE_DEPRECATED_OPENCL_1_2_APIS18#define CL_USE_DEPRECATED_OPENCL_2_0_APIS // eliminate build warning1920#ifdef __APPLE__21#include <OpenCL/cl.h>22#else23#include <CL/cl.h>24#endif2526#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>313233using namespace std;34using namespace cv;3536namespace opencl {3738class PlatformInfo39{40public:41PlatformInfo()42{}4344~PlatformInfo()45{}4647cl_int QueryInfo(cl_platform_id id)48{49query_param(id, CL_PLATFORM_PROFILE, m_profile);50query_param(id, CL_PLATFORM_VERSION, m_version);51query_param(id, CL_PLATFORM_NAME, m_name);52query_param(id, CL_PLATFORM_VENDOR, m_vendor);53query_param(id, CL_PLATFORM_EXTENSIONS, m_extensions);54return CL_SUCCESS;55}5657std::string Profile() { return m_profile; }58std::string Version() { return m_version; }59std::string Name() { return m_name; }60std::string Vendor() { return m_vendor; }61std::string Extensions() { return m_extensions; }6263private:64cl_int query_param(cl_platform_id id, cl_platform_info param, std::string& paramStr)65{66cl_int res;6768size_t psize;69cv::AutoBuffer<char> buf;7071res = clGetPlatformInfo(id, param, 0, 0, &psize);72if (CL_SUCCESS != res)73throw std::runtime_error(std::string("clGetPlatformInfo failed"));7475buf.resize(psize);76res = clGetPlatformInfo(id, param, psize, buf, 0);77if (CL_SUCCESS != res)78throw std::runtime_error(std::string("clGetPlatformInfo failed"));7980// just in case, ensure trailing zero for ASCIIZ string81buf[psize] = 0;8283paramStr = buf;8485return CL_SUCCESS;86}8788private:89std::string m_profile;90std::string m_version;91std::string m_name;92std::string m_vendor;93std::string m_extensions;94};959697class DeviceInfo98{99public:100DeviceInfo()101{}102103~DeviceInfo()104{}105106cl_int QueryInfo(cl_device_id id)107{108query_param(id, CL_DEVICE_TYPE, m_type);109query_param(id, CL_DEVICE_VENDOR_ID, m_vendor_id);110query_param(id, CL_DEVICE_MAX_COMPUTE_UNITS, m_max_compute_units);111query_param(id, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, m_max_work_item_dimensions);112query_param(id, CL_DEVICE_MAX_WORK_ITEM_SIZES, m_max_work_item_sizes);113query_param(id, CL_DEVICE_MAX_WORK_GROUP_SIZE, m_max_work_group_size);114query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, m_preferred_vector_width_char);115query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, m_preferred_vector_width_short);116query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, m_preferred_vector_width_int);117query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, m_preferred_vector_width_long);118query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, m_preferred_vector_width_float);119query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, m_preferred_vector_width_double);120#if defined(CL_VERSION_1_1)121query_param(id, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, m_preferred_vector_width_half);122query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, m_native_vector_width_char);123query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, m_native_vector_width_short);124query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, m_native_vector_width_int);125query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, m_native_vector_width_long);126query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, m_native_vector_width_float);127query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, m_native_vector_width_double);128query_param(id, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, m_native_vector_width_half);129#endif130query_param(id, CL_DEVICE_MAX_CLOCK_FREQUENCY, m_max_clock_frequency);131query_param(id, CL_DEVICE_ADDRESS_BITS, m_address_bits);132query_param(id, CL_DEVICE_MAX_MEM_ALLOC_SIZE, m_max_mem_alloc_size);133query_param(id, CL_DEVICE_IMAGE_SUPPORT, m_image_support);134query_param(id, CL_DEVICE_MAX_READ_IMAGE_ARGS, m_max_read_image_args);135query_param(id, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, m_max_write_image_args);136#if defined(CL_VERSION_2_0)137query_param(id, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, m_max_read_write_image_args);138#endif139query_param(id, CL_DEVICE_IMAGE2D_MAX_WIDTH, m_image2d_max_width);140query_param(id, CL_DEVICE_IMAGE2D_MAX_HEIGHT, m_image2d_max_height);141query_param(id, CL_DEVICE_IMAGE3D_MAX_WIDTH, m_image3d_max_width);142query_param(id, CL_DEVICE_IMAGE3D_MAX_HEIGHT, m_image3d_max_height);143query_param(id, CL_DEVICE_IMAGE3D_MAX_DEPTH, m_image3d_max_depth);144#if defined(CL_VERSION_1_2)145query_param(id, CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, m_image_max_buffer_size);146query_param(id, CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, m_image_max_array_size);147#endif148query_param(id, CL_DEVICE_MAX_SAMPLERS, m_max_samplers);149#if defined(CL_VERSION_1_2)150query_param(id, CL_DEVICE_IMAGE_PITCH_ALIGNMENT, m_image_pitch_alignment);151query_param(id, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, m_image_base_address_alignment);152#endif153#if defined(CL_VERSION_2_0)154query_param(id, CL_DEVICE_MAX_PIPE_ARGS, m_max_pipe_args);155query_param(id, CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS, m_pipe_max_active_reservations);156query_param(id, CL_DEVICE_PIPE_MAX_PACKET_SIZE, m_pipe_max_packet_size);157#endif158query_param(id, CL_DEVICE_MAX_PARAMETER_SIZE, m_max_parameter_size);159query_param(id, CL_DEVICE_MEM_BASE_ADDR_ALIGN, m_mem_base_addr_align);160query_param(id, CL_DEVICE_SINGLE_FP_CONFIG, m_single_fp_config);161#if defined(CL_VERSION_1_2)162query_param(id, CL_DEVICE_DOUBLE_FP_CONFIG, m_double_fp_config);163#endif164query_param(id, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, m_global_mem_cache_type);165query_param(id, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, m_global_mem_cacheline_size);166query_param(id, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, m_global_mem_cache_size);167query_param(id, CL_DEVICE_GLOBAL_MEM_SIZE, m_global_mem_size);168query_param(id, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, m_max_constant_buffer_size);169query_param(id, CL_DEVICE_MAX_CONSTANT_ARGS, m_max_constant_args);170#if defined(CL_VERSION_2_0)171query_param(id, CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, m_max_global_variable_size);172query_param(id, CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, m_global_variable_preferred_total_size);173#endif174query_param(id, CL_DEVICE_LOCAL_MEM_TYPE, m_local_mem_type);175query_param(id, CL_DEVICE_LOCAL_MEM_SIZE, m_local_mem_size);176query_param(id, CL_DEVICE_ERROR_CORRECTION_SUPPORT, m_error_correction_support);177#if defined(CL_VERSION_1_1)178query_param(id, CL_DEVICE_HOST_UNIFIED_MEMORY, m_host_unified_memory);179#endif180query_param(id, CL_DEVICE_PROFILING_TIMER_RESOLUTION, m_profiling_timer_resolution);181query_param(id, CL_DEVICE_ENDIAN_LITTLE, m_endian_little);182query_param(id, CL_DEVICE_AVAILABLE, m_available);183query_param(id, CL_DEVICE_COMPILER_AVAILABLE, m_compiler_available);184#if defined(CL_VERSION_1_2)185query_param(id, CL_DEVICE_LINKER_AVAILABLE, m_linker_available);186#endif187query_param(id, CL_DEVICE_EXECUTION_CAPABILITIES, m_execution_capabilities);188query_param(id, CL_DEVICE_QUEUE_PROPERTIES, m_queue_properties);189#if defined(CL_VERSION_2_0)190query_param(id, CL_DEVICE_QUEUE_ON_HOST_PROPERTIES, m_queue_on_host_properties);191query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, m_queue_on_device_properties);192query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE, m_queue_on_device_preferred_size);193query_param(id, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, m_queue_on_device_max_size);194query_param(id, CL_DEVICE_MAX_ON_DEVICE_QUEUES, m_max_on_device_queues);195query_param(id, CL_DEVICE_MAX_ON_DEVICE_EVENTS, m_max_on_device_events);196#endif197#if defined(CL_VERSION_1_2)198query_param(id, CL_DEVICE_BUILT_IN_KERNELS, m_built_in_kernels);199#endif200query_param(id, CL_DEVICE_PLATFORM, m_platform);201query_param(id, CL_DEVICE_NAME, m_name);202query_param(id, CL_DEVICE_VENDOR, m_vendor);203query_param(id, CL_DRIVER_VERSION, m_driver_version);204query_param(id, CL_DEVICE_PROFILE, m_profile);205query_param(id, CL_DEVICE_VERSION, m_version);206#if defined(CL_VERSION_1_1)207query_param(id, CL_DEVICE_OPENCL_C_VERSION, m_opencl_c_version);208#endif209query_param(id, CL_DEVICE_EXTENSIONS, m_extensions);210#if defined(CL_VERSION_1_2)211query_param(id, CL_DEVICE_PRINTF_BUFFER_SIZE, m_printf_buffer_size);212query_param(id, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, m_preferred_interop_user_sync);213query_param(id, CL_DEVICE_PARENT_DEVICE, m_parent_device);214query_param(id, CL_DEVICE_PARTITION_MAX_SUB_DEVICES, m_partition_max_sub_devices);215query_param(id, CL_DEVICE_PARTITION_PROPERTIES, m_partition_properties);216query_param(id, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, m_partition_affinity_domain);217query_param(id, CL_DEVICE_PARTITION_TYPE, m_partition_type);218query_param(id, CL_DEVICE_REFERENCE_COUNT, m_reference_count);219#endif220return CL_SUCCESS;221}222223std::string Name() { return m_name; }224225private:226template<typename T>227cl_int query_param(cl_device_id id, cl_device_info param, T& value)228{229cl_int res;230size_t size = 0;231232res = clGetDeviceInfo(id, param, 0, 0, &size);233if (CL_SUCCESS != res && size != 0)234throw std::runtime_error(std::string("clGetDeviceInfo failed"));235236if (0 == size)237return CL_SUCCESS;238239if (sizeof(T) != size)240throw std::runtime_error(std::string("clGetDeviceInfo: param size mismatch"));241242res = clGetDeviceInfo(id, param, size, &value, 0);243if (CL_SUCCESS != res)244throw std::runtime_error(std::string("clGetDeviceInfo failed"));245246return CL_SUCCESS;247}248249template<typename T>250cl_int query_param(cl_device_id id, cl_device_info param, std::vector<T>& value)251{252cl_int res;253size_t size;254255res = clGetDeviceInfo(id, param, 0, 0, &size);256if (CL_SUCCESS != res)257throw std::runtime_error(std::string("clGetDeviceInfo failed"));258259if (0 == size)260return CL_SUCCESS;261262value.resize(size / sizeof(T));263264res = clGetDeviceInfo(id, param, size, &value[0], 0);265if (CL_SUCCESS != res)266throw std::runtime_error(std::string("clGetDeviceInfo failed"));267268return CL_SUCCESS;269}270271cl_int query_param(cl_device_id id, cl_device_info param, std::string& value)272{273cl_int res;274size_t size;275276res = clGetDeviceInfo(id, param, 0, 0, &size);277if (CL_SUCCESS != res)278throw std::runtime_error(std::string("clGetDeviceInfo failed"));279280value.resize(size + 1);281282res = clGetDeviceInfo(id, param, size, &value[0], 0);283if (CL_SUCCESS != res)284throw std::runtime_error(std::string("clGetDeviceInfo failed"));285286// just in case, ensure trailing zero for ASCIIZ string287value[size] = 0;288289return CL_SUCCESS;290}291292private:293cl_device_type m_type;294cl_uint m_vendor_id;295cl_uint m_max_compute_units;296cl_uint m_max_work_item_dimensions;297std::vector<size_t> m_max_work_item_sizes;298size_t m_max_work_group_size;299cl_uint m_preferred_vector_width_char;300cl_uint m_preferred_vector_width_short;301cl_uint m_preferred_vector_width_int;302cl_uint m_preferred_vector_width_long;303cl_uint m_preferred_vector_width_float;304cl_uint m_preferred_vector_width_double;305#if defined(CL_VERSION_1_1)306cl_uint m_preferred_vector_width_half;307cl_uint m_native_vector_width_char;308cl_uint m_native_vector_width_short;309cl_uint m_native_vector_width_int;310cl_uint m_native_vector_width_long;311cl_uint m_native_vector_width_float;312cl_uint m_native_vector_width_double;313cl_uint m_native_vector_width_half;314#endif315cl_uint m_max_clock_frequency;316cl_uint m_address_bits;317cl_ulong m_max_mem_alloc_size;318cl_bool m_image_support;319cl_uint m_max_read_image_args;320cl_uint m_max_write_image_args;321#if defined(CL_VERSION_2_0)322cl_uint m_max_read_write_image_args;323#endif324size_t m_image2d_max_width;325size_t m_image2d_max_height;326size_t m_image3d_max_width;327size_t m_image3d_max_height;328size_t m_image3d_max_depth;329#if defined(CL_VERSION_1_2)330size_t m_image_max_buffer_size;331size_t m_image_max_array_size;332#endif333cl_uint m_max_samplers;334#if defined(CL_VERSION_1_2)335cl_uint m_image_pitch_alignment;336cl_uint m_image_base_address_alignment;337#endif338#if defined(CL_VERSION_2_0)339cl_uint m_max_pipe_args;340cl_uint m_pipe_max_active_reservations;341cl_uint m_pipe_max_packet_size;342#endif343size_t m_max_parameter_size;344cl_uint m_mem_base_addr_align;345cl_device_fp_config m_single_fp_config;346#if defined(CL_VERSION_1_2)347cl_device_fp_config m_double_fp_config;348#endif349cl_device_mem_cache_type m_global_mem_cache_type;350cl_uint m_global_mem_cacheline_size;351cl_ulong m_global_mem_cache_size;352cl_ulong m_global_mem_size;353cl_ulong m_max_constant_buffer_size;354cl_uint m_max_constant_args;355#if defined(CL_VERSION_2_0)356size_t m_max_global_variable_size;357size_t m_global_variable_preferred_total_size;358#endif359cl_device_local_mem_type m_local_mem_type;360cl_ulong m_local_mem_size;361cl_bool m_error_correction_support;362#if defined(CL_VERSION_1_1)363cl_bool m_host_unified_memory;364#endif365size_t m_profiling_timer_resolution;366cl_bool m_endian_little;367cl_bool m_available;368cl_bool m_compiler_available;369#if defined(CL_VERSION_1_2)370cl_bool m_linker_available;371#endif372cl_device_exec_capabilities m_execution_capabilities;373cl_command_queue_properties m_queue_properties;374#if defined(CL_VERSION_2_0)375cl_command_queue_properties m_queue_on_host_properties;376cl_command_queue_properties m_queue_on_device_properties;377cl_uint m_queue_on_device_preferred_size;378cl_uint m_queue_on_device_max_size;379cl_uint m_max_on_device_queues;380cl_uint m_max_on_device_events;381#endif382#if defined(CL_VERSION_1_2)383std::string m_built_in_kernels;384#endif385cl_platform_id m_platform;386std::string m_name;387std::string m_vendor;388std::string m_driver_version;389std::string m_profile;390std::string m_version;391#if defined(CL_VERSION_1_1)392std::string m_opencl_c_version;393#endif394std::string m_extensions;395#if defined(CL_VERSION_1_2)396size_t m_printf_buffer_size;397cl_bool m_preferred_interop_user_sync;398cl_device_id m_parent_device;399cl_uint m_partition_max_sub_devices;400std::vector<cl_device_partition_property> m_partition_properties;401cl_device_affinity_domain m_partition_affinity_domain;402std::vector<cl_device_partition_property> m_partition_type;403cl_uint m_reference_count;404#endif405};406407} // namespace opencl408409410class App411{412public:413App(CommandLineParser& cmd);414~App();415416int initOpenCL();417int initVideoSource();418419int process_frame_with_open_cl(cv::Mat& frame, bool use_buffer, cl_mem* cl_buffer);420int process_cl_buffer_with_opencv(cl_mem buffer, size_t step, int rows, int cols, int type, cv::UMat& u);421int process_cl_image_with_opencv(cl_mem image, cv::UMat& u);422423int run();424425bool isRunning() { return m_running; }426bool doProcess() { return m_process; }427bool useBuffer() { return m_use_buffer; }428429void setRunning(bool running) { m_running = running; }430void setDoProcess(bool process) { m_process = process; }431void setUseBuffer(bool use_buffer) { m_use_buffer = use_buffer; }432433protected:434bool nextFrame(cv::Mat& frame) { return m_cap.read(frame); }435void handleKey(char key);436void timerStart();437void timerEnd();438std::string timeStr() const;439std::string message() const;440441private:442bool m_running;443bool m_process;444bool m_use_buffer;445446int64 m_t0;447int64 m_t1;448float m_time;449float m_frequency;450451string m_file_name;452int m_camera_id;453cv::VideoCapture m_cap;454cv::Mat m_frame;455cv::Mat m_frameGray;456457opencl::PlatformInfo m_platformInfo;458opencl::DeviceInfo m_deviceInfo;459std::vector<cl_platform_id> m_platform_ids;460cl_context m_context;461cl_device_id m_device_id;462cl_command_queue m_queue;463cl_program m_program;464cl_kernel m_kernelBuf;465cl_kernel m_kernelImg;466cl_mem m_img_src; // used as src in case processing of cl image467cl_mem m_mem_obj;468cl_event m_event;469};470471472App::App(CommandLineParser& cmd)473{474cout << "\nPress ESC to exit\n" << endl;475cout << "\n 'p' to toggle ON/OFF processing\n" << endl;476cout << "\n SPACE to switch between OpenCL buffer/image\n" << endl;477478m_camera_id = cmd.get<int>("camera");479m_file_name = cmd.get<string>("video");480481m_running = false;482m_process = false;483m_use_buffer = false;484485m_t0 = 0;486m_t1 = 0;487m_time = 0.0;488m_frequency = (float)cv::getTickFrequency();489490m_context = 0;491m_device_id = 0;492m_queue = 0;493m_program = 0;494m_kernelBuf = 0;495m_kernelImg = 0;496m_img_src = 0;497m_mem_obj = 0;498m_event = 0;499} // ctor500501502App::~App()503{504if (m_queue)505{506clFinish(m_queue);507clReleaseCommandQueue(m_queue);508m_queue = 0;509}510511if (m_program)512{513clReleaseProgram(m_program);514m_program = 0;515}516517if (m_img_src)518{519clReleaseMemObject(m_img_src);520m_img_src = 0;521}522523if (m_mem_obj)524{525clReleaseMemObject(m_mem_obj);526m_mem_obj = 0;527}528529if (m_event)530{531clReleaseEvent(m_event);532}533534if (m_kernelBuf)535{536clReleaseKernel(m_kernelBuf);537m_kernelBuf = 0;538}539540if (m_kernelImg)541{542clReleaseKernel(m_kernelImg);543m_kernelImg = 0;544}545546if (m_device_id)547{548clReleaseDevice(m_device_id);549m_device_id = 0;550}551552if (m_context)553{554clReleaseContext(m_context);555m_context = 0;556}557} // dtor558559560int App::initOpenCL()561{562cl_int res = CL_SUCCESS;563cl_uint num_entries = 0;564565res = clGetPlatformIDs(0, 0, &num_entries);566if (CL_SUCCESS != res)567return -1;568569m_platform_ids.resize(num_entries);570571res = clGetPlatformIDs(num_entries, &m_platform_ids[0], 0);572if (CL_SUCCESS != res)573return -1;574575unsigned int i;576577// create context from first platform with GPU device578for (i = 0; i < m_platform_ids.size(); i++)579{580cl_context_properties props[] =581{582CL_CONTEXT_PLATFORM,583(cl_context_properties)(m_platform_ids[i]),5840585};586587m_context = clCreateContextFromType(props, CL_DEVICE_TYPE_GPU, 0, 0, &res);588if (0 == m_context || CL_SUCCESS != res)589continue;590591res = clGetContextInfo(m_context, CL_CONTEXT_DEVICES, sizeof(cl_device_id), &m_device_id, 0);592if (CL_SUCCESS != res)593return -1;594595m_queue = clCreateCommandQueue(m_context, m_device_id, 0, &res);596if (0 == m_queue || CL_SUCCESS != res)597return -1;598599const char* kernelSrc =600"__kernel "601"void bitwise_inv_buf_8uC1("602" __global unsigned char* pSrcDst,"603" int srcDstStep,"604" int rows,"605" int cols)"606"{"607" int x = get_global_id(0);"608" int y = get_global_id(1);"609" int idx = mad24(y, srcDstStep, x);"610" pSrcDst[idx] = ~pSrcDst[idx];"611"}"612"__kernel "613"void bitwise_inv_img_8uC1("614" read_only image2d_t srcImg,"615" write_only image2d_t dstImg)"616"{"617" int x = get_global_id(0);"618" int y = get_global_id(1);"619" int2 coord = (int2)(x, y);"620" uint4 val = read_imageui(srcImg, coord);"621" val.x = (~val.x) & 0x000000FF;"622" write_imageui(dstImg, coord, val);"623"}";624size_t len = strlen(kernelSrc);625m_program = clCreateProgramWithSource(m_context, 1, &kernelSrc, &len, &res);626if (0 == m_program || CL_SUCCESS != res)627return -1;628629res = clBuildProgram(m_program, 1, &m_device_id, 0, 0, 0);630if (CL_SUCCESS != res)631return -1;632633m_kernelBuf = clCreateKernel(m_program, "bitwise_inv_buf_8uC1", &res);634if (0 == m_kernelBuf || CL_SUCCESS != res)635return -1;636637m_kernelImg = clCreateKernel(m_program, "bitwise_inv_img_8uC1", &res);638if (0 == m_kernelImg || CL_SUCCESS != res)639return -1;640641m_platformInfo.QueryInfo(m_platform_ids[i]);642m_deviceInfo.QueryInfo(m_device_id);643644// attach OpenCL context to OpenCV645cv::ocl::attachContext(m_platformInfo.Name(), m_platform_ids[i], m_context, m_device_id);646647break;648}649650return m_context != 0 ? CL_SUCCESS : -1;651} // initOpenCL()652653654int App::initVideoSource()655{656try657{658if (!m_file_name.empty() && m_camera_id == -1)659{660m_cap.open(m_file_name.c_str());661if (!m_cap.isOpened())662throw std::runtime_error(std::string("can't open video file: " + m_file_name));663}664else if (m_camera_id != -1)665{666m_cap.open(m_camera_id);667if (!m_cap.isOpened())668{669std::stringstream msg;670msg << "can't open camera: " << m_camera_id;671throw std::runtime_error(msg.str());672}673}674else675throw std::runtime_error(std::string("specify video source"));676}677678catch (std::exception e)679{680cerr << "ERROR: " << e.what() << std::endl;681return -1;682}683684return 0;685} // initVideoSource()686687688// this function is an example of "typical" OpenCL processing pipeline689// It creates OpenCL buffer or image, depending on use_buffer flag,690// from input media frame and process these data691// (inverts each pixel value in half of frame) with OpenCL kernel692int App::process_frame_with_open_cl(cv::Mat& frame, bool use_buffer, cl_mem* mem_obj)693{694cl_int res = CL_SUCCESS;695696CV_Assert(mem_obj);697698cl_kernel kernel = 0;699cl_mem mem = mem_obj[0];700701if (0 == mem || 0 == m_img_src)702{703// allocate/delete cl memory objects every frame for the simplicity.704// in real applicaton more efficient pipeline can be built.705706if (use_buffer)707{708cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR;709710mem = clCreateBuffer(m_context, flags, frame.total(), frame.ptr(), &res);711if (0 == mem || CL_SUCCESS != res)712return -1;713714res = clSetKernelArg(m_kernelBuf, 0, sizeof(cl_mem), &mem);715if (CL_SUCCESS != res)716return -1;717718res = clSetKernelArg(m_kernelBuf, 1, sizeof(int), &frame.step[0]);719if (CL_SUCCESS != res)720return -1;721722res = clSetKernelArg(m_kernelBuf, 2, sizeof(int), &frame.rows);723if (CL_SUCCESS != res)724return -1;725726int cols2 = frame.cols / 2;727res = clSetKernelArg(m_kernelBuf, 3, sizeof(int), &cols2);728if (CL_SUCCESS != res)729return -1;730731kernel = m_kernelBuf;732}733else734{735cl_mem_flags flags_src = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;736737cl_image_format fmt;738fmt.image_channel_order = CL_R;739fmt.image_channel_data_type = CL_UNSIGNED_INT8;740741cl_image_desc desc_src;742desc_src.image_type = CL_MEM_OBJECT_IMAGE2D;743desc_src.image_width = frame.cols;744desc_src.image_height = frame.rows;745desc_src.image_depth = 0;746desc_src.image_array_size = 0;747desc_src.image_row_pitch = frame.step[0];748desc_src.image_slice_pitch = 0;749desc_src.num_mip_levels = 0;750desc_src.num_samples = 0;751desc_src.buffer = 0;752m_img_src = clCreateImage(m_context, flags_src, &fmt, &desc_src, frame.ptr(), &res);753if (0 == m_img_src || CL_SUCCESS != res)754return -1;755756cl_mem_flags flags_dst = CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR;757758cl_image_desc desc_dst;759desc_dst.image_type = CL_MEM_OBJECT_IMAGE2D;760desc_dst.image_width = frame.cols;761desc_dst.image_height = frame.rows;762desc_dst.image_depth = 0;763desc_dst.image_array_size = 0;764desc_dst.image_row_pitch = 0;765desc_dst.image_slice_pitch = 0;766desc_dst.num_mip_levels = 0;767desc_dst.num_samples = 0;768desc_dst.buffer = 0;769mem = clCreateImage(m_context, flags_dst, &fmt, &desc_dst, 0, &res);770if (0 == mem || CL_SUCCESS != res)771return -1;772773size_t origin[] = { 0, 0, 0 };774size_t region[] = { (size_t)frame.cols, (size_t)frame.rows, 1 };775res = clEnqueueCopyImage(m_queue, m_img_src, mem, origin, origin, region, 0, 0, &m_event);776if (CL_SUCCESS != res)777return -1;778779res = clWaitForEvents(1, &m_event);780if (CL_SUCCESS != res)781return -1;782783res = clSetKernelArg(m_kernelImg, 0, sizeof(cl_mem), &m_img_src);784if (CL_SUCCESS != res)785return -1;786787res = clSetKernelArg(m_kernelImg, 1, sizeof(cl_mem), &mem);788if (CL_SUCCESS != res)789return -1;790791kernel = m_kernelImg;792}793}794795m_event = clCreateUserEvent(m_context, &res);796if (0 == m_event || CL_SUCCESS != res)797return -1;798799// process left half of frame in OpenCL800size_t size[] = { (size_t)frame.cols / 2, (size_t)frame.rows };801res = clEnqueueNDRangeKernel(m_queue, kernel, 2, 0, size, 0, 0, 0, &m_event);802if (CL_SUCCESS != res)803return -1;804805res = clWaitForEvents(1, &m_event);806if (CL_SUCCESS != res)807return - 1;808809mem_obj[0] = mem;810811return 0;812}813814815// this function is an example of interoperability between OpenCL buffer816// and OpenCV UMat objects. It converts (without copying data) OpenCL buffer817// to OpenCV UMat and then do blur on these data818int App::process_cl_buffer_with_opencv(cl_mem buffer, size_t step, int rows, int cols, int type, cv::UMat& u)819{820cv::ocl::convertFromBuffer(buffer, step, rows, cols, type, u);821822// process right half of frame in OpenCV823cv::Point pt(u.cols / 2, 0);824cv::Size sz(u.cols / 2, u.rows);825cv::Rect roi(pt, sz);826cv::UMat uroi(u, roi);827cv::blur(uroi, uroi, cv::Size(7, 7), cv::Point(-3, -3));828829if (buffer)830clReleaseMemObject(buffer);831m_mem_obj = 0;832833return 0;834}835836837// this function is an example of interoperability between OpenCL image838// and OpenCV UMat objects. It converts OpenCL image839// to OpenCV UMat and then do blur on these data840int App::process_cl_image_with_opencv(cl_mem image, cv::UMat& u)841{842cv::ocl::convertFromImage(image, u);843844// process right half of frame in OpenCV845cv::Point pt(u.cols / 2, 0);846cv::Size sz(u.cols / 2, u.rows);847cv::Rect roi(pt, sz);848cv::UMat uroi(u, roi);849cv::blur(uroi, uroi, cv::Size(7, 7), cv::Point(-3, -3));850851if (image)852clReleaseMemObject(image);853m_mem_obj = 0;854855if (m_img_src)856clReleaseMemObject(m_img_src);857m_img_src = 0;858859return 0;860}861862863int App::run()864{865if (0 != initOpenCL())866return -1;867868if (0 != initVideoSource())869return -1;870871Mat img_to_show;872873// set running state until ESC pressed874setRunning(true);875// set process flag to show some data processing876// can be toggled on/off by 'p' button877setDoProcess(true);878// set use buffer flag,879// when it is set to true, will demo interop opencl buffer and cv::Umat,880// otherwise demo interop opencl image and cv::UMat881// can be switched on/of by SPACE button882setUseBuffer(true);883884// Iterate over all frames885while (isRunning() && nextFrame(m_frame))886{887cv::cvtColor(m_frame, m_frameGray, COLOR_BGR2GRAY);888889UMat uframe;890891// work892timerStart();893894if (doProcess())895{896process_frame_with_open_cl(m_frameGray, useBuffer(), &m_mem_obj);897898if (useBuffer())899process_cl_buffer_with_opencv(900m_mem_obj, m_frameGray.step[0], m_frameGray.rows, m_frameGray.cols, m_frameGray.type(), uframe);901else902process_cl_image_with_opencv(m_mem_obj, uframe);903}904else905{906m_frameGray.copyTo(uframe);907}908909timerEnd();910911uframe.copyTo(img_to_show);912913putText(img_to_show, "Version : " + m_platformInfo.Version(), Point(5, 30), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);914putText(img_to_show, "Name : " + m_platformInfo.Name(), Point(5, 60), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);915putText(img_to_show, "Device : " + m_deviceInfo.Name(), Point(5, 90), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);916cv::String memtype = useBuffer() ? "buffer" : "image";917putText(img_to_show, "interop with OpenCL " + memtype, Point(5, 120), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);918putText(img_to_show, "Time : " + timeStr() + " msec", Point(5, 150), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);919920imshow("opencl_interop", img_to_show);921922handleKey((char)waitKey(3));923}924925return 0;926}927928929void App::handleKey(char key)930{931switch (key)932{933case 27:934setRunning(false);935break;936937case ' ':938setUseBuffer(!useBuffer());939break;940941case 'p':942case 'P':943setDoProcess( !doProcess() );944break;945946default:947break;948}949}950951952inline void App::timerStart()953{954m_t0 = getTickCount();955}956957958inline void App::timerEnd()959{960m_t1 = getTickCount();961int64 delta = m_t1 - m_t0;962m_time = (delta / m_frequency) * 1000; // units msec963}964965966inline string App::timeStr() const967{968stringstream ss;969ss << std::fixed << std::setprecision(1) << m_time;970return ss.str();971}972973974int main(int argc, char** argv)975{976const char* keys =977"{ help h ? | | print help message }"978"{ camera c | -1 | use camera as input }"979"{ video v | | use video as input }";980981CommandLineParser cmd(argc, argv, keys);982if (cmd.has("help"))983{984cmd.printMessage();985return EXIT_SUCCESS;986}987988App app(cmd);989990try991{992app.run();993}994995catch (const cv::Exception& e)996{997cout << "error: " << e.what() << endl;998return 1;999}10001001catch (const std::exception& e)1002{1003cout << "error: " << e.what() << endl;1004return 1;1005}10061007catch (...)1008{1009cout << "unknown exception" << endl;1010return 1;1011}10121013return EXIT_SUCCESS;1014} // main()101510161017