opencv_sobel_filter.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Mageswaran.D <mageswaran1989@gmail.com>
  3. //
  4. // Book Refered: OpenCL Programming Guide
  5. // Distributed under the Boost Software License, Version 1.0
  6. // See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt
  8. //
  9. // See http://boostorg.github.com/compute for more information.
  10. //---------------------------------------------------------------------------//
  11. //---------------------------------------------------------------------------//
  12. // About Sobel Filter:
  13. // * Edge Filter - distinguishes the differrent color region
  14. // * Finds the gradient in x and y-axes
  15. // * Three step process
  16. // -> Find x-axis gradient with kernel/matrix
  17. // Gx = [-1 0 +1]
  18. // [-2 0 +2]
  19. // [-1 0 +1]
  20. // -> Find y-axis gradient with kernel/matrix
  21. // Gy = [-1 -2 -1]
  22. // [ 0 0 0]
  23. // [+1 +2 +1]
  24. // * Gradient magnitude G = sqrt(Gx^2 + Gy^2)
  25. //---------------------------------------------------------------------------//
  26. #include <iostream>
  27. #include <string>
  28. #include <opencv2/core/core.hpp>
  29. #include <opencv2/highgui/highgui.hpp>
  30. #include <opencv2/imgproc/imgproc.hpp>
  31. #include <boost/compute/system.hpp>
  32. #include <boost/compute/interop/opencv/core.hpp>
  33. #include <boost/compute/interop/opencv/highgui.hpp>
  34. #include <boost/compute/utility/source.hpp>
  35. #include <boost/program_options.hpp>
  36. namespace compute = boost::compute;
  37. namespace po = boost::program_options;
  38. // Create sobel filter program
  39. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE (
  40. //For out of boundary pixels, edge pixel
  41. // value is returned
  42. const sampler_t sampler = CLK_ADDRESS_CLAMP_TO_EDGE |
  43. CLK_FILTER_NEAREST;
  44. kernel void sobel_rgb(read_only image2d_t src, write_only image2d_t dst)
  45. {
  46. int x = (int)get_global_id(0);
  47. int y = (int)get_global_id(1);
  48. if (x >= get_image_width(src) || y >= get_image_height(src))
  49. return;
  50. // [(x-1, y+1), (x, y+1), (x+1, y+1)]
  51. // [(x-1, y ), (x, y ), (x+1, y )]
  52. // [(x-1, y-1), (x, y-1), (x+1, y-1)]
  53. // [p02, p12, p22]
  54. // [p01, pixel, p21]
  55. // [p00, p10, p20]
  56. //Basically finding influence of neighbour pixels on current pixel
  57. float4 p00 = read_imagef(src, sampler, (int2)(x - 1, y - 1));
  58. float4 p10 = read_imagef(src, sampler, (int2)(x, y - 1));
  59. float4 p20 = read_imagef(src, sampler, (int2)(x + 1, y - 1));
  60. float4 p01 = read_imagef(src, sampler, (int2)(x - 1, y));
  61. //pixel that we are working on
  62. float4 p21 = read_imagef(src, sampler, (int2)(x + 1, y));
  63. float4 p02 = read_imagef(src, sampler, (int2)(x - 1, y + 1));
  64. float4 p12 = read_imagef(src, sampler, (int2)(x, y + 1));
  65. float4 p22 = read_imagef(src, sampler, (int2)(x + 1, y + 1));
  66. //Find Gx = kernel + 3x3 around current pixel
  67. // Gx = [-1 0 +1] [p02, p12, p22]
  68. // [-2 0 +2] + [p01, pixel, p21]
  69. // [-1 0 +1] [p00, p10, p20]
  70. float3 gx = -p00.xyz + p20.xyz +
  71. 2.0f * (p21.xyz - p01.xyz)
  72. -p02.xyz + p22.xyz;
  73. //Find Gy = kernel + 3x3 around current pixel
  74. // Gy = [-1 -2 -1] [p02, p12, p22]
  75. // [ 0 0 0] + [p01, pixel, p21]
  76. // [+1 +2 +1] [p00, p10, p20]
  77. float3 gy = p00.xyz + p20.xyz +
  78. 2.0f * (- p12.xyz + p10.xyz) -
  79. p02.xyz - p22.xyz;
  80. //Find G
  81. float3 g = native_sqrt(gx * gx + gy * gy);
  82. // we could also approximate this as g = fabs(gx) + fabs(gy)
  83. write_imagef(dst, (int2)(x, y), (float4)(g.x, g.y, g.z, 1.0f));
  84. }
  85. );
  86. // This example shows how to apply sobel filter on images or on camera frames
  87. // with OpenCV, transfer the frames to the GPU, and apply a sobel filter
  88. // written in OpenCL
  89. int main(int argc, char *argv[])
  90. {
  91. ///////////////////////////////////////////////////////////////////////////
  92. // setup the command line arguments
  93. po::options_description desc;
  94. desc.add_options()
  95. ("help", "show available options")
  96. ("camera", po::value<int>()->default_value(-1),
  97. "if not default camera, specify a camera id")
  98. ("image", po::value<std::string>(), "path to image file");
  99. // Parse the command lines
  100. po::variables_map vm;
  101. po::store(po::parse_command_line(argc, argv, desc), vm);
  102. po::notify(vm);
  103. //check the command line arguments
  104. if(vm.count("help"))
  105. {
  106. std::cout << desc << std::endl;
  107. return 0;
  108. }
  109. ///////////////////////////////////////////////////////////////////////////
  110. //OpenCV variables
  111. cv::Mat cv_mat;
  112. cv::VideoCapture cap; //OpenCV camera handle.
  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::program filter_program =
  119. compute::program::create_with_source(source, context);
  120. try
  121. {
  122. filter_program.build();
  123. }
  124. catch(compute::opencl_error e)
  125. {
  126. std::cout<<"Build Error: "<<std::endl
  127. <<filter_program.build_log();
  128. }
  129. // create fliter kernel and set arguments
  130. compute::kernel filter_kernel(filter_program, "sobel_rgb");
  131. ///////////////////////////////////////////////////////////////////////////
  132. //check for image paths
  133. if(vm.count("image"))
  134. {
  135. // Read image with OpenCV
  136. cv_mat = cv::imread(vm["image"].as<std::string>(),
  137. CV_LOAD_IMAGE_COLOR);
  138. if(!cv_mat.data){
  139. std::cerr << "Failed to load image" << std::endl;
  140. return -1;
  141. }
  142. }
  143. else //by default use camera
  144. {
  145. //open camera
  146. cap.open(vm["camera"].as<int>());
  147. // read first frame
  148. cap >> cv_mat;
  149. if(!cv_mat.data){
  150. std::cerr << "failed to capture frame" << std::endl;
  151. return -1;
  152. }
  153. }
  154. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  155. cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA);
  156. // Transfer image/frame data to gpu
  157. compute::image2d dev_input_image =
  158. compute::opencv_create_image2d_with_mat(
  159. cv_mat, compute::image2d::read_write, queue
  160. );
  161. // Create output image
  162. // Be sure what will be your ouput image/frame size
  163. compute::image2d dev_output_image(
  164. context,
  165. dev_input_image.width(),
  166. dev_input_image.height(),
  167. dev_input_image.format(),
  168. compute::image2d::write_only
  169. );
  170. filter_kernel.set_arg(0, dev_input_image);
  171. filter_kernel.set_arg(1, dev_output_image);
  172. // run flip kernel
  173. size_t origin[2] = { 0, 0 };
  174. size_t region[2] = { dev_input_image.width(),
  175. dev_input_image.height() };
  176. ///////////////////////////////////////////////////////////////////////////
  177. queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0);
  178. //check for image paths
  179. if(vm.count("image"))
  180. {
  181. // show host image
  182. cv::imshow("Original Image", cv_mat);
  183. // show gpu image
  184. compute::opencv_imshow("Filtered Image", dev_output_image, queue);
  185. // wait and return
  186. cv::waitKey(0);
  187. }
  188. else
  189. {
  190. char key = '\0';
  191. while(key != 27) //check for escape key
  192. {
  193. cap >> cv_mat;
  194. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  195. cv::cvtColor(cv_mat, cv_mat, CV_BGR2BGRA);
  196. // Update the device image memory with current frame data
  197. compute::opencv_copy_mat_to_image(cv_mat,
  198. dev_input_image,queue);
  199. // Run the kernel on the device
  200. queue.enqueue_nd_range_kernel(filter_kernel, 2, origin, region, 0);
  201. // Show host image
  202. cv::imshow("Camera Frame", cv_mat);
  203. // Show GPU image
  204. compute::opencv_imshow("Filtered RGB Frame", dev_output_image, queue);
  205. // wait
  206. key = cv::waitKey(10);
  207. }
  208. }
  209. return 0;
  210. }