opencv_optical_flow.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 naive optical flow program
  23. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE (
  24. const sampler_t sampler = CLK_ADDRESS_CLAMP_TO_EDGE;
  25. __kernel void optical_flow (
  26. read_only
  27. image2d_t current_image,
  28. read_only image2d_t previous_image,
  29. write_only image2d_t optical_flow,
  30. const float scale,
  31. const float offset,
  32. const float lambda,
  33. const float threshold )
  34. {
  35. int2 coords = (int2)(get_global_id(0), get_global_id(1));
  36. float4 current_pixel = read_imagef(current_image,
  37. sampler,
  38. coords);
  39. float4 previous_pixel = read_imagef(previous_image,
  40. sampler,
  41. coords);
  42. int2 x1 = (int2)(offset, 0.f);
  43. int2 y1 = (int2)(0.f, offset);
  44. //get the difference
  45. float4 curdif = previous_pixel - current_pixel;
  46. //calculate the gradient
  47. //Image 2 first
  48. float4 gradx = read_imagef(previous_image,
  49. sampler,
  50. coords+x1) -
  51. read_imagef(previous_image,
  52. sampler,
  53. coords-x1);
  54. //Image 1
  55. gradx += read_imagef(current_image,
  56. sampler,
  57. coords+x1) -
  58. read_imagef(current_image,
  59. sampler,
  60. coords-x1);
  61. //Image 2 first
  62. float4 grady = read_imagef(previous_image,
  63. sampler,
  64. coords+y1) -
  65. read_imagef(previous_image,
  66. sampler,
  67. coords-y1);
  68. //Image 1
  69. grady += read_imagef(current_image,
  70. sampler,
  71. coords+y1) -
  72. read_imagef(current_image,
  73. sampler,
  74. coords-y1);
  75. float4 sqr = (gradx*gradx) + (grady*grady) +
  76. (float4)(lambda,lambda, lambda, lambda);
  77. float4 gradmag = sqrt(sqr);
  78. ///////////////////////////////////////////////////
  79. float4 vx = curdif * (gradx / gradmag);
  80. float vxd = vx.x;//assumes greyscale
  81. //format output for flowrepos, out(-x,+x,-y,+y)
  82. float2 xout = (float2)(fmax(vxd,0.f),fabs(fmin(vxd,0.f)));
  83. xout *= scale;
  84. ///////////////////////////////////////////////////
  85. float4 vy = curdif*(grady/gradmag);
  86. float vyd = vy.x;//assumes greyscale
  87. //format output for flowrepos, out(-x,+x,-y,+y)
  88. float2 yout = (float2)(fmax(vyd,0.f),fabs(fmin(vyd,0.f)));
  89. yout *= scale;
  90. ///////////////////////////////////////////////////
  91. float4 out = (float4)(xout, yout);
  92. float cond = (float)isgreaterequal(length(out), threshold);
  93. out *= cond;
  94. write_imagef(optical_flow, coords, out);
  95. }
  96. );
  97. // This example shows how to read two images or use camera
  98. // with OpenCV, transfer the frames to the GPU,
  99. // and apply a naive optical flow algorithm
  100. // written in OpenCL
  101. int main(int argc, char *argv[])
  102. {
  103. // setup the command line arguments
  104. po::options_description desc;
  105. desc.add_options()
  106. ("help", "show available options")
  107. ("camera", po::value<int>()->default_value(-1),
  108. "if not default camera, specify a camera id")
  109. ("image1", po::value<std::string>(), "path to image file 1")
  110. ("image2", po::value<std::string>(), "path to image file 2");
  111. // Parse the command lines
  112. po::variables_map vm;
  113. po::store(po::parse_command_line(argc, argv, desc), vm);
  114. po::notify(vm);
  115. //check the command line arguments
  116. if(vm.count("help"))
  117. {
  118. std::cout << desc << std::endl;
  119. return 0;
  120. }
  121. //OpenCV variables
  122. cv::Mat previous_cv_image;
  123. cv::Mat current_cv_image;
  124. cv::VideoCapture cap; //OpenCV camera handle
  125. //check for image paths
  126. if(vm.count("image1") && vm.count("image2"))
  127. {
  128. // Read image 1 with OpenCV
  129. previous_cv_image = cv::imread(vm["image1"].as<std::string>(),
  130. CV_LOAD_IMAGE_COLOR);
  131. if(!previous_cv_image.data){
  132. std::cerr << "Failed to load image" << std::endl;
  133. return -1;
  134. }
  135. // Read image 2 with opencv
  136. current_cv_image = cv::imread(vm["image2"].as<std::string>(),
  137. CV_LOAD_IMAGE_COLOR);
  138. if(!current_cv_image.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 >> previous_cv_image;
  149. if(!previous_cv_image.data){
  150. std::cerr << "failed to capture frame" << std::endl;
  151. return -1;
  152. }
  153. // read second frame
  154. cap >> current_cv_image;
  155. if(!current_cv_image.data){
  156. std::cerr << "failed to capture frame" << std::endl;
  157. return -1;
  158. }
  159. }
  160. // Get default device and setup context
  161. compute::device gpu = compute::system::default_device();
  162. compute::context context(gpu);
  163. compute::command_queue queue(context, gpu);
  164. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  165. cv::cvtColor(previous_cv_image, previous_cv_image, CV_BGR2BGRA);
  166. cv::cvtColor(current_cv_image, current_cv_image, CV_BGR2BGRA);
  167. // Transfer image to gpu
  168. compute::image2d dev_previous_image =
  169. compute::opencv_create_image2d_with_mat(
  170. previous_cv_image, compute::image2d::read_write, queue
  171. );
  172. // Transfer image to gpu
  173. compute::image2d dev_current_image =
  174. compute::opencv_create_image2d_with_mat(
  175. current_cv_image, compute::image2d::read_write, queue
  176. );
  177. // Create output image
  178. compute::image2d dev_output_image(
  179. context,
  180. dev_previous_image.width(),
  181. dev_previous_image.height(),
  182. dev_previous_image.format(),
  183. compute::image2d::write_only
  184. );
  185. compute::program optical_program =
  186. compute::program::create_with_source(source, context);
  187. optical_program.build();
  188. // create flip kernel and set arguments
  189. compute::kernel optical_kernel(optical_program, "optical_flow");
  190. float scale = 10;
  191. float offset = 1;
  192. float lambda = 0.0025;
  193. float threshold = 1.0;
  194. optical_kernel.set_arg(0, dev_previous_image);
  195. optical_kernel.set_arg(1, dev_current_image);
  196. optical_kernel.set_arg(2, dev_output_image);
  197. optical_kernel.set_arg(3, scale);
  198. optical_kernel.set_arg(4, offset);
  199. optical_kernel.set_arg(5, lambda);
  200. optical_kernel.set_arg(6, threshold);
  201. // run flip kernel
  202. size_t origin[2] = { 0, 0 };
  203. size_t region[2] = { dev_previous_image.width(),
  204. dev_previous_image.height() };
  205. queue.enqueue_nd_range_kernel(optical_kernel, 2, origin, region, 0);
  206. //check for image paths
  207. if(vm.count("image1") && vm.count("image2"))
  208. {
  209. // show host image
  210. cv::imshow("Previous Frame", previous_cv_image);
  211. cv::imshow("Current Frame", current_cv_image);
  212. // show gpu image
  213. compute::opencv_imshow("filtered image", dev_output_image, queue);
  214. // wait and return
  215. cv::waitKey(0);
  216. }
  217. else
  218. {
  219. char key = '\0';
  220. while(key != 27) //check for escape key
  221. {
  222. cap >> current_cv_image;
  223. // Convert image to BGRA (OpenCL requires 16-byte aligned data)
  224. cv::cvtColor(current_cv_image, current_cv_image, CV_BGR2BGRA);
  225. // Update the device image memory with current frame data
  226. compute::opencv_copy_mat_to_image(previous_cv_image,
  227. dev_previous_image,
  228. queue);
  229. compute::opencv_copy_mat_to_image(current_cv_image,
  230. dev_current_image,
  231. queue);
  232. // Run the kernel on the device
  233. queue.enqueue_nd_range_kernel(optical_kernel, 2, origin, region, 0);
  234. // Show host image
  235. cv::imshow("Previous Frame", previous_cv_image);
  236. cv::imshow("Current Frame", current_cv_image);
  237. // Show GPU image
  238. compute::opencv_imshow("filtered image", dev_output_image, queue);
  239. // Copy current frame container to previous frame container
  240. current_cv_image.copyTo(previous_cv_image);
  241. // wait
  242. key = cv::waitKey(10);
  243. }
  244. }
  245. return 0;
  246. }