algorithm.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. // Copyright 2019 Pranam Lashkari <plashkari628@gmail.com>
  4. //
  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. #ifndef BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP
  10. #define BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP
  11. #include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
  12. #include <boost/gil/metafunctions.hpp>
  13. #include <boost/gil/pixel_iterator.hpp>
  14. #include <boost/gil/image.hpp>
  15. #include <boost/assert.hpp>
  16. #include <algorithm>
  17. #include <iterator>
  18. #include <numeric>
  19. #include <type_traits>
  20. namespace boost { namespace gil {
  21. /// \brief Reference proxy associated with a type that has a \p "reference" member type alias.
  22. ///
  23. /// The reference proxy is the reference type, but with stripped-out C++ reference.
  24. /// Models PixelConcept.
  25. template <typename T>
  26. struct pixel_proxy : std::remove_reference<typename T::reference> {};
  27. /// \brief std::for_each for a pair of iterators
  28. template <typename Iterator1, typename Iterator2, typename BinaryFunction>
  29. BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
  30. {
  31. while (first1 != last1)
  32. f(*first1++, *first2++);
  33. return f;
  34. }
  35. template <typename SrcIterator, typename DstIterator>
  36. inline
  37. auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
  38. {
  39. for_each(src, src_end, dst,
  40. pixel_assigns_t
  41. <
  42. typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
  43. typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
  44. >());
  45. return dst + (src_end - src);
  46. }
  47. namespace detail {
  48. template <std::size_t Size>
  49. struct inner_product_k_t
  50. {
  51. template
  52. <
  53. class InputIterator1,
  54. class InputIterator2,
  55. class T,
  56. class BinaryOperation1,
  57. class BinaryOperation2
  58. >
  59. static T apply(
  60. InputIterator1 first1,
  61. InputIterator2 first2, T init,
  62. BinaryOperation1 binary_op1,
  63. BinaryOperation2 binary_op2)
  64. {
  65. init = binary_op1(init, binary_op2(*first1, *first2));
  66. return inner_product_k_t<Size - 1>::template apply(
  67. first1 + 1, first2 + 1, init, binary_op1, binary_op2);
  68. }
  69. };
  70. template <>
  71. struct inner_product_k_t<0>
  72. {
  73. template
  74. <
  75. class InputIterator1,
  76. class InputIterator2,
  77. class T,
  78. class BinaryOperation1,
  79. class BinaryOperation2
  80. >
  81. static T apply(
  82. InputIterator1 first1,
  83. InputIterator2 first2,
  84. T init,
  85. BinaryOperation1 binary_op1,
  86. BinaryOperation2 binary_op2)
  87. {
  88. return init;
  89. }
  90. };
  91. } // namespace detail
  92. /// static version of std::inner_product
  93. template
  94. <
  95. std::size_t Size,
  96. class InputIterator1,
  97. class InputIterator2,
  98. class T,
  99. class BinaryOperation1,
  100. class BinaryOperation2
  101. >
  102. BOOST_FORCEINLINE
  103. T inner_product_k(
  104. InputIterator1 first1,
  105. InputIterator2 first2,
  106. T init,
  107. BinaryOperation1 binary_op1,
  108. BinaryOperation2 binary_op2)
  109. {
  110. return detail::inner_product_k_t<Size>::template apply(
  111. first1, first2, init, binary_op1, binary_op2);
  112. }
  113. /// \brief 1D un-guarded cross-correlation with a variable-size kernel
  114. template
  115. <
  116. typename PixelAccum,
  117. typename SrcIterator,
  118. typename KernelIterator,
  119. typename Size,
  120. typename DstIterator
  121. >
  122. inline
  123. auto correlate_pixels_n(
  124. SrcIterator src_begin,
  125. SrcIterator src_end,
  126. KernelIterator kernel_begin,
  127. Size kernel_size,
  128. DstIterator dst_begin)
  129. -> DstIterator
  130. {
  131. using src_pixel_ref_t = typename pixel_proxy
  132. <
  133. typename std::iterator_traits<SrcIterator>::value_type
  134. >::type;
  135. using dst_pixel_ref_t = typename pixel_proxy
  136. <
  137. typename std::iterator_traits<DstIterator>::value_type
  138. >::type;
  139. using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
  140. PixelAccum accum_zero;
  141. pixel_zeros_t<PixelAccum>()(accum_zero);
  142. while (src_begin != src_end)
  143. {
  144. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  145. std::inner_product(
  146. src_begin,
  147. src_begin + kernel_size,
  148. kernel_begin,
  149. accum_zero,
  150. pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
  151. pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
  152. *dst_begin);
  153. ++src_begin;
  154. ++dst_begin;
  155. }
  156. return dst_begin;
  157. }
  158. /// \brief 1D un-guarded cross-correlation with a fixed-size kernel
  159. template
  160. <
  161. std::size_t Size,
  162. typename PixelAccum,
  163. typename SrcIterator,
  164. typename KernelIterator,
  165. typename DstIterator
  166. >
  167. inline
  168. auto correlate_pixels_k(
  169. SrcIterator src_begin,
  170. SrcIterator src_end,
  171. KernelIterator kernel_begin,
  172. DstIterator dst_begin)
  173. -> DstIterator
  174. {
  175. using src_pixel_ref_t = typename pixel_proxy
  176. <
  177. typename std::iterator_traits<SrcIterator>::value_type
  178. >::type;
  179. using dst_pixel_ref_t = typename pixel_proxy
  180. <
  181. typename std::iterator_traits<DstIterator>::value_type
  182. >::type;
  183. using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
  184. PixelAccum accum_zero;
  185. pixel_zeros_t<PixelAccum>()(accum_zero);
  186. while (src_begin != src_end)
  187. {
  188. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  189. inner_product_k<Size>(
  190. src_begin,
  191. kernel_begin,
  192. accum_zero,
  193. pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
  194. pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
  195. *dst_begin);
  196. ++src_begin;
  197. ++dst_begin;
  198. }
  199. return dst_begin;
  200. }
  201. /// \brief destination is set to be product of the source and a scalar
  202. /// \tparam PixelAccum - TODO
  203. /// \tparam SrcView Models ImageViewConcept
  204. /// \tparam DstView Models MutableImageViewConcept
  205. template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
  206. inline
  207. void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
  208. {
  209. static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
  210. BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
  211. using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
  212. using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
  213. using y_coord_t = typename SrcView::y_coord_t;
  214. y_coord_t const height = src_view.height();
  215. for (y_coord_t y = 0; y < height; ++y)
  216. {
  217. typename SrcView::x_iterator it_src = src_view.row_begin(y);
  218. typename DstView::x_iterator it_dst = dst_view.row_begin(y);
  219. typename SrcView::x_iterator it_src_end = src_view.row_end(y);
  220. while (it_src != it_src_end)
  221. {
  222. pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
  223. pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
  224. *it_dst);
  225. ++it_src;
  226. ++it_dst;
  227. }
  228. }
  229. }
  230. /// \ingroup ImageAlgorithms
  231. /// \brief Boundary options for image boundary extension
  232. enum class boundary_option
  233. {
  234. output_ignore, /// do nothing to the output
  235. output_zero, /// set the output to zero
  236. extend_padded, /// assume the source boundaries to be padded already
  237. extend_zero, /// assume the source boundaries to be zero
  238. extend_constant /// assume the source boundaries to be the boundary value
  239. };
  240. namespace detail
  241. {
  242. template <typename SrcView, typename RltView>
  243. void extend_row_impl(
  244. SrcView src_view,
  245. RltView result_view,
  246. std::size_t extend_count,
  247. boundary_option option)
  248. {
  249. std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
  250. if (option == boundary_option::extend_constant)
  251. {
  252. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  253. {
  254. if(i >= extend_count_ && i < extend_count_ + src_view.height())
  255. {
  256. assign_pixels(
  257. src_view.row_begin(i - extend_count_),
  258. src_view.row_end(i - extend_count_),
  259. result_view.row_begin(i)
  260. );
  261. }
  262. else if(i < extend_count_)
  263. {
  264. assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
  265. }
  266. else
  267. {
  268. assign_pixels(
  269. src_view.row_begin(src_view.height() - 1),
  270. src_view.row_end(src_view.height() - 1),
  271. result_view.row_begin(i)
  272. );
  273. }
  274. }
  275. }
  276. else if (option == boundary_option::extend_zero)
  277. {
  278. typename SrcView::value_type acc_zero;
  279. pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
  280. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  281. {
  282. if (i >= extend_count_ && i < extend_count_ + src_view.height())
  283. {
  284. assign_pixels(
  285. src_view.row_begin(i - extend_count_),
  286. src_view.row_end(i - extend_count_),
  287. result_view.row_begin(i)
  288. );
  289. }
  290. else
  291. {
  292. std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
  293. }
  294. }
  295. }
  296. else if (option == boundary_option::extend_padded)
  297. {
  298. auto original_view = subimage_view(
  299. src_view,
  300. 0,
  301. -extend_count,
  302. src_view.width(),
  303. src_view.height() + (2 * extend_count)
  304. );
  305. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  306. {
  307. assign_pixels(
  308. original_view.row_begin(i),
  309. original_view.row_end(i),
  310. result_view.row_begin(i)
  311. );
  312. }
  313. }
  314. else
  315. {
  316. BOOST_ASSERT_MSG(false, "Invalid boundary option");
  317. }
  318. }
  319. } //namespace detail
  320. /// \brief adds new row at top and bottom.
  321. /// Image padding introduces new pixels around the edges of an image.
  322. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  323. /// \tparam SrcView Models ImageViewConcept
  324. /// \tparam extend_count number of rows to be added each side
  325. /// \tparam option - TODO
  326. template <typename SrcView>
  327. auto extend_row(
  328. SrcView src_view,
  329. std::size_t extend_count,
  330. boundary_option option
  331. ) -> typename gil::image<typename SrcView::value_type>
  332. {
  333. typename gil::image<typename SrcView::value_type>
  334. result_img(src_view.width(), src_view.height() + (2 * extend_count));
  335. auto result_view = view(result_img);
  336. detail::extend_row_impl(src_view, result_view, extend_count, option);
  337. return result_img;
  338. }
  339. /// \brief adds new column at left and right.
  340. /// Image padding introduces new pixels around the edges of an image.
  341. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  342. /// \tparam SrcView Models ImageViewConcept
  343. /// \tparam extend_count number of columns to be added each side
  344. /// \tparam option - TODO
  345. template <typename SrcView>
  346. auto extend_col(
  347. SrcView src_view,
  348. std::size_t extend_count,
  349. boundary_option option
  350. ) -> typename gil::image<typename SrcView::value_type>
  351. {
  352. auto src_view_rotate = rotated90cw_view(src_view);
  353. typename gil::image<typename SrcView::value_type>
  354. result_img(src_view.width() + (2 * extend_count), src_view.height());
  355. auto result_view = rotated90cw_view(view(result_img));
  356. detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
  357. return result_img;
  358. }
  359. /// \brief adds new row and column at all sides.
  360. /// Image padding introduces new pixels around the edges of an image.
  361. /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
  362. /// \tparam SrcView Models ImageViewConcept
  363. /// \tparam extend_count number of rows/column to be added each side
  364. /// \tparam option - TODO
  365. template <typename SrcView>
  366. auto extend_boundary(
  367. SrcView src_view,
  368. std::size_t extend_count,
  369. boundary_option option
  370. ) -> typename gil::image<typename SrcView::value_type>
  371. {
  372. if (option == boundary_option::extend_padded)
  373. {
  374. typename gil::image<typename SrcView::value_type>
  375. result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
  376. typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
  377. auto original_view = subimage_view(
  378. src_view,
  379. -extend_count,
  380. -extend_count,
  381. src_view.width() + (2 * extend_count),
  382. src_view.height() + (2 * extend_count)
  383. );
  384. for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
  385. {
  386. assign_pixels(
  387. original_view.row_begin(i),
  388. original_view.row_end(i),
  389. result_view.row_begin(i)
  390. );
  391. }
  392. return result_img;
  393. }
  394. auto auxilary_img = extend_col(src_view, extend_count, option);
  395. return extend_row(view(auxilary_img), extend_count, option);
  396. }
  397. }} // namespace boost::gil
  398. #endif