sampler.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. // Copyright 2021 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_SAMPLER_HPP
  10. #define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
  11. #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
  12. #include <boost/gil/pixel_numeric_operations.hpp>
  13. namespace boost { namespace gil {
  14. // Nearest-neighbor and bilinear image samplers.
  15. // NOTE: The code is for example use only. It is not optimized for performance
  16. ///////////////////////////////////////////////////////////////////////////
  17. ////
  18. //// resample_pixels: set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view
  19. ////
  20. ///////////////////////////////////////////////////////////////////////////
  21. /*
  22. template <typename Sampler>
  23. concept SamplerConcept {
  24. template <typename DstP, // Models PixelConcept
  25. typename SrcView, // Models RandomAccessNDImageViewConcept
  26. typename S_COORDS> // Models PointNDConcept, where S_COORDS::num_dimensions == SrcView::num_dimensions
  27. bool sample(const Sampler& s, const SrcView& src, const S_COORDS& p, DstP result);
  28. };
  29. */
  30. /// \brief A sampler that sets the destination pixel to the closest one in the source. If outside the bounds, it doesn't change the destination
  31. /// \ingroup ImageAlgorithms
  32. struct nearest_neighbor_sampler {};
  33. template <typename DstP, typename SrcView, typename F>
  34. bool sample(nearest_neighbor_sampler, SrcView const& src, point<F> const& p, DstP& result)
  35. {
  36. typename SrcView::point_t center(iround(p));
  37. if (center.x >= 0 && center.y >= 0 && center.x < src.width() && center.y < src.height())
  38. {
  39. result=src(center.x,center.y);
  40. return true;
  41. }
  42. return false;
  43. }
  44. struct cast_channel_fn {
  45. template <typename SrcChannel, typename DstChannel>
  46. void operator()(const SrcChannel& src, DstChannel& dst) {
  47. using dst_value_t = typename channel_traits<DstChannel>::value_type;
  48. dst = dst_value_t(src);
  49. }
  50. };
  51. template <typename SrcPixel, typename DstPixel>
  52. void cast_pixel(const SrcPixel& src, DstPixel& dst) {
  53. static_for_each(src,dst,cast_channel_fn());
  54. }
  55. namespace detail {
  56. template <typename Weight>
  57. struct add_dst_mul_src_channel {
  58. Weight _w;
  59. add_dst_mul_src_channel(Weight w) : _w(w) {}
  60. template <typename SrcChannel, typename DstChannel>
  61. void operator()(const SrcChannel& src, DstChannel& dst) const {
  62. dst += DstChannel(src*_w);
  63. }
  64. };
  65. // dst += DST_TYPE(src * w)
  66. template <typename SrcP,typename Weight,typename DstP>
  67. struct add_dst_mul_src {
  68. void operator()(const SrcP& src, Weight weight, DstP& dst) const {
  69. static_for_each(src,dst, add_dst_mul_src_channel<Weight>(weight));
  70. // pixel_assigns_t<DstP,DstP&>()(
  71. // pixel_plus_t<DstP,DstP,DstP>()(
  72. // pixel_multiplies_scalar_t<SrcP,Weight,DstP>()(src,weight),
  73. // dst),
  74. // dst);
  75. }
  76. };
  77. } // namespace detail
  78. /// \brief A sampler that sets the destination pixel as the bilinear interpolation of the four closest pixels from the source.
  79. /// If outside the bounds, it doesn't change the destination
  80. /// \ingroup ImageAlgorithms
  81. struct bilinear_sampler {};
  82. template <typename DstP, typename SrcView, typename F>
  83. bool sample(bilinear_sampler, SrcView const& src, point<F> const& p, DstP& result)
  84. {
  85. using SrcP = typename SrcView::value_type;
  86. point_t p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p
  87. point<F> frac(p.x-p0.x, p.y-p0.y);
  88. if (p0.x < -1 || p0.y < -1 || p0.x>=src.width() || p0.y>=src.height())
  89. {
  90. return false;
  91. }
  92. pixel<F,devicen_layout_t<num_channels<SrcView>::value> > mp(0); // suboptimal
  93. typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y);
  94. if (p0.x == -1)
  95. {
  96. if (p0.y == -1)
  97. {
  98. // the top-left corner pixel
  99. ++loc.y();
  100. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp);
  101. }
  102. else if (p0.y+1<src.height())
  103. {
  104. // on the first column, but not the top-left nor bottom-left corner pixel
  105. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], (1-frac.y),mp);
  106. ++loc.y();
  107. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.y ,mp);
  108. }
  109. else
  110. {
  111. // the bottom-left corner pixel
  112. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp);
  113. }
  114. }
  115. else if (p0.x+1<src.width())
  116. {
  117. if (p0.y == -1)
  118. {
  119. // on the first row, but not the top-left nor top-right corner pixel
  120. ++loc.y();
  121. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp);
  122. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp);
  123. }
  124. else if (p0.y+1<src.height())
  125. {
  126. // most common case - inside the image, not on the frist nor last row/column
  127. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)*(1-frac.y),mp);
  128. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x *(1-frac.y),mp);
  129. ++loc.y();
  130. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)* frac.y ,mp);
  131. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x * frac.y ,mp);
  132. }
  133. else
  134. {
  135. // on the last row, but not the bottom-left nor bottom-right corner pixel
  136. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp);
  137. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp);
  138. }
  139. }
  140. else
  141. {
  142. if (p0.y == -1)
  143. {
  144. // the top-right corner pixel
  145. ++loc.y();
  146. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp);
  147. }
  148. else if (p0.y+1<src.height())
  149. {
  150. // on the last column, but not the top-right nor bottom-right corner pixel
  151. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.y),mp);
  152. ++loc.y();
  153. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, frac.y ,mp);
  154. }
  155. else
  156. {
  157. // the bottom-right corner pixel
  158. detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp);
  159. }
  160. }
  161. // Convert from floating point average value to the source type
  162. SrcP src_result;
  163. cast_pixel(mp,src_result);
  164. color_convert(src_result, result);
  165. return true;
  166. }
  167. }} // namespace boost::gil
  168. #endif