opencv_histogram.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. //Code sample for calculating histogram using OpenCL and
  11. //displaying image histogram in OpenCV.
  12. #include <iostream>
  13. #include <string>
  14. #include <opencv2/imgproc/imgproc.hpp>
  15. #include <opencv2/highgui/highgui.hpp>
  16. #include <boost/compute/source.hpp>
  17. #include <boost/compute/system.hpp>
  18. #include <boost/compute/container/vector.hpp>
  19. #include <boost/compute/interop/opencv/core.hpp>
  20. #include <boost/compute/interop/opencv/highgui.hpp>
  21. #include <boost/program_options.hpp>
  22. namespace compute = boost::compute;
  23. namespace po = boost::program_options;
  24. // number of bins
  25. int histSize = 256;
  26. // Set the ranges ( for B,G,R) )
  27. // TryOut: consider the range in kernel calculation
  28. float range[] = { 0, 256 } ;
  29. const float* histRange = { range };
  30. // Create naive histogram program
  31. // Needs "cl_khr_local_int32_base_atomics" extension
  32. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE (
  33. __kernel void histogram(read_only image2d_t src_image,
  34. __global int* b_hist,
  35. __global int* g_hist,
  36. __global int* r_hist)
  37. {
  38. sampler_t sampler =( CLK_NORMALIZED_COORDS_FALSE |
  39. CLK_FILTER_NEAREST |
  40. CLK_ADDRESS_CLAMP_TO_EDGE);
  41. int image_width = get_image_width(src_image);
  42. int image_height = get_image_height(src_image);
  43. int2 coords = (int2)(get_global_id(0), get_global_id(1));
  44. float4 pixel = read_imagef(src_image,sampler, coords);
  45. //boundary condition
  46. if ((coords.x < image_width) && (coords.y < image_height))
  47. {
  48. uchar indx_x, indx_y, indx_z;
  49. indx_x = convert_uchar_sat(pixel.x * 255.0f);
  50. indx_y = convert_uchar_sat(pixel.y * 255.0f);
  51. indx_z = convert_uchar_sat(pixel.z * 255.0f);
  52. atomic_inc(&b_hist[(uint)indx_z]);
  53. atomic_inc(&g_hist[(uint)indx_y]);
  54. atomic_inc(&r_hist[(uint)indx_x]);
  55. }
  56. }
  57. );
  58. inline void showHistogramWindow(cv::Mat &b_hist, cv::Mat &g_hist, cv::Mat &r_hist,
  59. std::string window_name)
  60. {
  61. // Draw the histograms for B, G and R
  62. int hist_w = 1024;
  63. int hist_h = 768;
  64. int bin_w = cvRound((double)hist_w/histSize);
  65. cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(0,0,0));
  66. // Normalize the result to [ 0, histImage.rows ]
  67. cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
  68. cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
  69. cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
  70. // Draw for each channel
  71. for (int i = 1; i < histSize; i++ )
  72. {
  73. cv::line(histImage,
  74. cv::Point(bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1))),
  75. cv::Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))),
  76. cv::Scalar(255, 0, 0),
  77. 2,
  78. 8,
  79. 0);
  80. cv::line(histImage,
  81. cv::Point(bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1))),
  82. cv::Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))),
  83. cv::Scalar(0, 255, 0),
  84. 2,
  85. 8,
  86. 0);
  87. cv::line(histImage,
  88. cv::Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1))),
  89. cv::Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
  90. cv::Scalar( 0, 0, 255),
  91. 2,
  92. 8,
  93. 0);
  94. }
  95. // Display
  96. cv::namedWindow(window_name, CV_WINDOW_AUTOSIZE );
  97. cv::imshow(window_name, histImage );
  98. }
  99. //Get the device context
  100. //Create GPU array/vector
  101. //Copy the image & set up the kernel
  102. //Execute the kernel
  103. //Copy GPU data back to CPU cv::Mat data pointer
  104. //OpenCV conversion for convienient display
  105. void calculateHistogramUsingCL(cv::Mat src, compute::command_queue &queue)
  106. {
  107. compute::context context = queue.get_context();
  108. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  109. cv::cvtColor(src, src, CV_BGR2BGRA);
  110. //3 channels & 256 bins : alpha channel is ignored
  111. compute::vector<int> gpu_b_hist(histSize, context);
  112. compute::vector<int> gpu_g_hist(histSize, context);
  113. compute::vector<int> gpu_r_hist(histSize, context);
  114. // Transfer image to gpu
  115. compute::image2d gpu_src =
  116. compute::opencv_create_image2d_with_mat(
  117. src, compute::image2d::read_only,
  118. queue
  119. );
  120. compute::program histogram_program =
  121. compute::program::create_with_source(source, context);
  122. histogram_program.build();
  123. // create histogram kernel and set arguments
  124. compute::kernel histogram_kernel(histogram_program, "histogram");
  125. histogram_kernel.set_arg(0, gpu_src);
  126. histogram_kernel.set_arg(1, gpu_b_hist.get_buffer());
  127. histogram_kernel.set_arg(2, gpu_g_hist.get_buffer());
  128. histogram_kernel.set_arg(3, gpu_r_hist.get_buffer());
  129. // run histogram kernel
  130. // each kernel thread updating red, green & blue bins
  131. size_t origin[2] = { 0, 0 };
  132. size_t region[2] = { gpu_src.width(),
  133. gpu_src.height() };
  134. queue.enqueue_nd_range_kernel(histogram_kernel, 2, origin, region, 0);
  135. //Make sure kernel get executed and data copied back
  136. queue.finish();
  137. //create Mat and copy GPU bins to CPU memory
  138. cv::Mat b_hist(256, 1, CV_32SC1);
  139. compute::copy(gpu_b_hist.begin(), gpu_b_hist.end(), b_hist.data, queue);
  140. cv::Mat g_hist(256, 1, CV_32SC1);
  141. compute::copy(gpu_g_hist.begin(), gpu_g_hist.end(), g_hist.data, queue);
  142. cv::Mat r_hist(256, 1, CV_32SC1);
  143. compute::copy(gpu_r_hist.begin(), gpu_r_hist.end(), r_hist.data, queue);
  144. b_hist.convertTo(b_hist, CV_32FC1); //converted for displaying
  145. g_hist.convertTo(g_hist, CV_32FC1);
  146. r_hist.convertTo(r_hist, CV_32FC1);
  147. showHistogramWindow(b_hist, g_hist, r_hist, "Histogram");
  148. }
  149. int main( int argc, char** argv )
  150. {
  151. // Get default device and setup context
  152. compute::device gpu = compute::system::default_device();
  153. compute::context context(gpu);
  154. compute::command_queue queue(context, gpu);
  155. cv::Mat src;
  156. // setup the command line arguments
  157. po::options_description desc;
  158. desc.add_options()
  159. ("help", "show available options")
  160. ("image", po::value<std::string>(), "path to image file");
  161. // Parse the command lines
  162. po::variables_map vm;
  163. po::store(po::parse_command_line(argc, argv, desc), vm);
  164. po::notify(vm);
  165. //check the command line arguments
  166. if(vm.count("help"))
  167. {
  168. std::cout << desc << std::endl;
  169. return 0;
  170. }
  171. //check for image paths
  172. if(vm.count("image"))
  173. {
  174. // Read image with OpenCV
  175. src = cv::imread(vm["image"].as<std::string>(),
  176. CV_LOAD_IMAGE_COLOR);
  177. if(!src.data){
  178. std::cerr << "Failed to load image" << std::endl;
  179. return -1;
  180. }
  181. calculateHistogramUsingCL(src, queue);
  182. cv::imshow("Image", src);
  183. cv::waitKey(0);
  184. }
  185. else
  186. {
  187. std::cout << desc << std::endl;
  188. return 0;
  189. }
  190. return 0;
  191. }