random_walk.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@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 <opencv2/core/core.hpp>
  12. #include <opencv2/highgui/highgui.hpp>
  13. #include <opencv2/imgproc/imgproc.hpp>
  14. #include <boost/compute/system.hpp>
  15. #include <boost/compute/algorithm/inclusive_scan.hpp>
  16. #include <boost/compute/algorithm/inclusive_scan.hpp>
  17. #include <boost/compute/interop/opencv/core.hpp>
  18. #include <boost/compute/interop/opencv/highgui.hpp>
  19. #include <boost/compute/random/default_random_engine.hpp>
  20. #include <boost/compute/random/uniform_real_distribution.hpp>
  21. #include <boost/compute/utility/source.hpp>
  22. namespace compute = boost::compute;
  23. // this example uses the random-number generation functions in Boost.Compute
  24. // to calculate a large number of random "steps" and then plots the final
  25. // random "walk" in a 2D image on the GPU and displays it with OpenCV
  26. int main()
  27. {
  28. // number of random steps to take
  29. size_t steps = 250000;
  30. // height and width of image
  31. size_t height = 800;
  32. size_t width = 800;
  33. // get default device and setup context
  34. compute::device gpu = compute::system::default_device();
  35. compute::context context(gpu);
  36. compute::command_queue queue(context, gpu);
  37. using compute::int2_;
  38. // calaculate random values for each step
  39. compute::vector<float> random_values(steps, context);
  40. compute::default_random_engine random_engine(queue);
  41. compute::uniform_real_distribution<float> random_distribution(0.f, 4.f);
  42. random_distribution.generate(
  43. random_values.begin(), random_values.end(), random_engine, queue
  44. );
  45. // calaculate coordinates for each step
  46. compute::vector<int2_> coordinates(steps, context);
  47. // function to convert random values to random directions (in 2D)
  48. BOOST_COMPUTE_FUNCTION(int2_, take_step, (const float x),
  49. {
  50. if(x < 1.f){
  51. // move right
  52. return (int2)(1, 0);
  53. }
  54. if(x < 2.f){
  55. // move up
  56. return (int2)(0, 1);
  57. }
  58. if(x < 3.f){
  59. // move left
  60. return (int2)(-1, 0);
  61. }
  62. else {
  63. // move down
  64. return (int2)(0, -1);
  65. }
  66. });
  67. // transform the random values into random steps
  68. compute::transform(
  69. random_values.begin(), random_values.end(), coordinates.begin(), take_step, queue
  70. );
  71. // set staring position
  72. int2_ starting_position(width / 2, height / 2);
  73. compute::copy_n(&starting_position, 1, coordinates.begin(), queue);
  74. // scan steps to calculate position after each step
  75. compute::inclusive_scan(
  76. coordinates.begin(), coordinates.end(), coordinates.begin(), queue
  77. );
  78. // create output image
  79. compute::image2d image(
  80. context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8)
  81. );
  82. // program with two kernels, one to fill the image with white, and then
  83. // one the draw to points calculated in coordinates on the image
  84. const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  85. __kernel void draw_walk(__global const int2 *coordinates,
  86. __write_only image2d_t image)
  87. {
  88. const uint i = get_global_id(0);
  89. const int2 coord = coordinates[i];
  90. if(coord.x > 0 && coord.x < get_image_width(image) &&
  91. coord.y > 0 && coord.y < get_image_height(image)){
  92. uint4 black = { 0, 0, 0, 0 };
  93. write_imageui(image, coord, black);
  94. }
  95. }
  96. __kernel void fill_white(__write_only image2d_t image)
  97. {
  98. const int2 coord = { get_global_id(0), get_global_id(1) };
  99. if(coord.x < get_image_width(image) &&
  100. coord.y < get_image_height(image)){
  101. uint4 white = { 255, 255, 255, 255 };
  102. write_imageui(image, coord, white);
  103. }
  104. }
  105. );
  106. // build the program
  107. compute::program draw_program =
  108. compute::program::build_with_source(draw_walk_source, context);
  109. // fill image with white
  110. compute::kernel fill_kernel(draw_program, "fill_white");
  111. fill_kernel.set_arg(0, image);
  112. const size_t offset[] = { 0, 0 };
  113. const size_t bounds[] = { width, height };
  114. queue.enqueue_nd_range_kernel(fill_kernel, 2, offset, bounds, 0);
  115. // draw random walk
  116. compute::kernel draw_kernel(draw_program, "draw_walk");
  117. draw_kernel.set_arg(0, coordinates);
  118. draw_kernel.set_arg(1, image);
  119. queue.enqueue_1d_range_kernel(draw_kernel, 0, coordinates.size(), 0);
  120. // show image
  121. compute::opencv_imshow("random walk", image, queue);
  122. // wait and return
  123. cv::waitKey(0);
  124. return 0;
  125. }