opencv_convolution.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Mageswaran.D <mageswaran1989@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #include <iostream>
  11. #include <string>
  12. #include <opencv2/core/core.hpp>
  13. #include <opencv2/highgui/highgui.hpp>
  14. #include <opencv2/imgproc/imgproc.hpp>
  15. #include <boost/compute/system.hpp>
  16. #include <boost/compute/interop/opencv/core.hpp>
  17. #include <boost/compute/interop/opencv/highgui.hpp>
  18. #include <boost/compute/utility/source.hpp>
  19. #include <boost/program_options.hpp>
  20. namespace compute = boost::compute;
  21. namespace po = boost::program_options;
  22. // Create convolution program
  23. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE (
  24. __kernel void convolution(__read_only image2d_t sourceImage,
  25. __write_only image2d_t outputImage,
  26. __constant float* filter,
  27. int filterWidth)
  28. {
  29. const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
  30. CLK_ADDRESS_CLAMP_TO_EDGE |
  31. CLK_FILTER_NEAREST;
  32. // Store each work-item's unique row and column
  33. int x = get_global_id(0);
  34. int y = get_global_id(1);
  35. // Half the width of the filter is needed for indexing
  36. // memory later
  37. int halfWidth = (int)(filterWidth/2);
  38. // All accesses to images return data as four-element vector
  39. // (i.e., float4).
  40. float4 sum = {0.0f, 0.0f, 0.0f, 0.0f};
  41. // Iterator for the filter
  42. int filterIdx = 0;
  43. // Each work-item iterates around its local area based on the
  44. // size of the filter
  45. int2 coords; // Coordinates for accessing the image
  46. // Iterate the filter rows
  47. for(int i = -halfWidth; i <= halfWidth; i++)
  48. {
  49. coords.y = y + i;
  50. // Iterate over the filter columns
  51. for(int j = -halfWidth; j <= halfWidth; j++)
  52. {
  53. coords.x = x + j;
  54. float4 pixel;
  55. // Read a pixel from the image.
  56. // Work on a channel
  57. pixel = read_imagef(sourceImage, sampler, coords);
  58. sum.x += pixel.x * filter[filterIdx++];
  59. //sum.y += pixel.y * filter[filterIdx++];
  60. //sum.z += pixel.z * filter[filterIdx++];
  61. }
  62. }
  63. barrier(CLK_GLOBAL_MEM_FENCE);
  64. // Copy the data to the output image if the
  65. // work-item is in bounds
  66. if(y < get_image_height(sourceImage) &&
  67. x < get_image_width(sourceImage))
  68. {
  69. coords.x = x;
  70. coords.y = y;
  71. //Same channel is copied in all three channels
  72. //write_imagef(outputImage, coords,
  73. // (float4)(sum.x,sum.x,sum.x,1.0f));
  74. write_imagef(outputImage, coords, sum);
  75. }
  76. }
  77. );
  78. // This example shows how to read two images or use camera
  79. // with OpenCV, transfer the frames to the GPU,
  80. // and apply a convolution written in OpenCL
  81. int main(int argc, char *argv[])
  82. {
  83. ///////////////////////////////////////////////////////////////////////////
  84. // setup the command line arguments
  85. po::options_description desc;
  86. desc.add_options()
  87. ("help", "show available options")
  88. ("camera", po::value<int>()->default_value(-1),
  89. "if not default camera, specify a camera id")
  90. ("image", po::value<std::string>(), "path to image file");
  91. // Parse the command lines
  92. po::variables_map vm;
  93. po::store(po::parse_command_line(argc, argv, desc), vm);
  94. po::notify(vm);
  95. //check the command line arguments
  96. if(vm.count("help"))
  97. {
  98. std::cout << desc << std::endl;
  99. return 0;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////
  102. //OpenCV variables
  103. cv::Mat cv_mat;
  104. cv::VideoCapture cap; //OpenCV camera handle.
  105. //Filter Variables
  106. float filter[9] = {
  107. -1.0, 0.0, 1.0,
  108. -2.0, 0.0, 2.0,
  109. -1.0, 0.0, 1.0,
  110. };
  111. // The convolution filter is 3x3
  112. int filterWidth = 3;
  113. //OpenCL variables
  114. // Get default device and setup context
  115. compute::device gpu = compute::system::default_device();
  116. compute::context context(gpu);
  117. compute::command_queue queue(context, gpu);
  118. compute::buffer dev_filter(context, sizeof(filter),
  119. compute::memory_object::read_only |
  120. compute::memory_object::copy_host_ptr,
  121. filter);
  122. compute::program filter_program =
  123. compute::program::create_with_source(source, context);
  124. try
  125. {
  126. filter_program.build();
  127. }
  128. catch(compute::opencl_error e)
  129. {
  130. std::cout<<"Build Error: "<<std::endl
  131. <<filter_program.build_log();
  132. return -1;
  133. }
  134. // create fliter kernel and set arguments
  135. compute::kernel filter_kernel(filter_program, "convolution");
  136. ///////////////////////////////////////////////////////////////////////////
  137. //check for image paths
  138. if(vm.count("image"))
  139. {
  140. // Read image with OpenCV
  141. cv_mat = cv::imread(vm["image"].as<std::string>(),
  142. CV_LOAD_IMAGE_COLOR);
  143. if(!cv_mat.data){
  144. std::cerr << "Failed to load image" << std::endl;
  145. return -1;
  146. }
  147. }
  148. else //by default use camera
  149. {
  150. //open camera
  151. cap.open(vm["camera"].as<int>());
  152. // read first frame
  153. cap >> cv_mat;
  154. if(!cv_mat.data){
  155. std::cerr << "failed to capture frame" << std::endl;
  156. return -1;
  157. }
  158. }
  159. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  160. cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA);
  161. // Transfer image/frame data to gpu
  162. compute::image2d dev_input_image =
  163. compute::opencv_create_image2d_with_mat(
  164. cv_mat, compute::image2d::read_write, queue
  165. );
  166. // Create output image
  167. // Be sure what will be your ouput image/frame size
  168. compute::image2d dev_output_image(
  169. context,
  170. dev_input_image.width(),
  171. dev_input_image.height(),
  172. dev_input_image.format(),
  173. compute::image2d::write_only
  174. );
  175. filter_kernel.set_arg(0, dev_input_image);
  176. filter_kernel.set_arg(1, dev_output_image);
  177. filter_kernel.set_arg(2, dev_filter);
  178. filter_kernel.set_arg(3, filterWidth);
  179. // run flip kernel
  180. size_t origin[2] = { 0, 0 };
  181. size_t region[2] = { dev_input_image.width(),
  182. dev_input_image.height() };
  183. ///////////////////////////////////////////////////////////////////////////
  184. queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0);
  185. //check for image paths
  186. if(vm.count("image"))
  187. {
  188. // show host image
  189. cv::imshow("Original Image", cv_mat);
  190. // show gpu image
  191. compute::opencv_imshow("Convoluted Image", dev_output_image, queue);
  192. // wait and return
  193. cv::waitKey(0);
  194. }
  195. else
  196. {
  197. char key = '\0';
  198. while(key != 27) //check for escape key
  199. {
  200. cap >> cv_mat;
  201. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  202. cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA);
  203. // Update the device image memory with current frame data
  204. compute::opencv_copy_mat_to_image(cv_mat,
  205. dev_input_image,queue);
  206. // Run the kernel on the device
  207. queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0);
  208. // Show host image
  209. cv::imshow("Camera Frame", cv_mat);
  210. // Show GPU image
  211. compute::opencv_imshow("Convoluted Frame", dev_output_image, queue);
  212. // wait
  213. key = cv::waitKey(10);
  214. }
  215. }
  216. return 0;
  217. }