2 // Copyright 2005-2007 Adobe Systems Incorporated
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
8 #ifndef BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
9 #define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
11 #include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
12 #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
14 namespace boost { namespace gil {
16 // Nearest-neighbor and bilinear image samplers.
17 // NOTE: The code is for example use only. It is not optimized for performance
19 ///////////////////////////////////////////////////////////////////////////
21 //// resample_pixels: set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view
23 ///////////////////////////////////////////////////////////////////////////
25 template <typename Sampler>
26 concept SamplerConcept {
27 template <typename DstP, // Models PixelConcept
28 typename SrcView, // Models RandomAccessNDImageViewConcept
29 typename S_COORDS> // Models PointNDConcept, where S_COORDS::num_dimensions == SrcView::num_dimensions
30 bool sample(const Sampler& s, const SrcView& src, const S_COORDS& p, DstP result);
34 /// \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
35 /// \ingroup ImageAlgorithms
36 struct nearest_neighbor_sampler {};
38 template <typename DstP, typename SrcView, typename F>
39 bool sample(nearest_neighbor_sampler, SrcView const& src, point<F> const& p, DstP& result)
41 typename SrcView::point_t center(iround(p));
42 if (center.x >= 0 && center.y >= 0 && center.x < src.width() && center.y < src.height())
44 result=src(center.x,center.y);
50 struct cast_channel_fn {
51 template <typename SrcChannel, typename DstChannel>
52 void operator()(const SrcChannel& src, DstChannel& dst) {
53 using dst_value_t = typename channel_traits<DstChannel>::value_type;
54 dst = dst_value_t(src);
58 template <typename SrcPixel, typename DstPixel>
59 void cast_pixel(const SrcPixel& src, DstPixel& dst) {
60 static_for_each(src,dst,cast_channel_fn());
65 template <typename Weight>
66 struct add_dst_mul_src_channel {
68 add_dst_mul_src_channel(Weight w) : _w(w) {}
70 template <typename SrcChannel, typename DstChannel>
71 void operator()(const SrcChannel& src, DstChannel& dst) const {
72 dst += DstChannel(src*_w);
76 // dst += DST_TYPE(src * w)
77 template <typename SrcP,typename Weight,typename DstP>
78 struct add_dst_mul_src {
79 void operator()(const SrcP& src, Weight weight, DstP& dst) const {
80 static_for_each(src,dst, add_dst_mul_src_channel<Weight>(weight));
81 // pixel_assigns_t<DstP,DstP&>()(
82 // pixel_plus_t<DstP,DstP,DstP>()(
83 // pixel_multiplies_scalar_t<SrcP,Weight,DstP>()(src,weight),
90 /// \brief A sampler that sets the destination pixel as the bilinear interpolation of the four closest pixels from the source.
91 /// If outside the bounds, it doesn't change the destination
92 /// \ingroup ImageAlgorithms
93 struct bilinear_sampler {};
95 template <typename DstP, typename SrcView, typename F>
96 bool sample(bilinear_sampler, SrcView const& src, point<F> const& p, DstP& result)
98 using SrcP = typename SrcView::value_type;
99 point_t p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p
100 point<F> frac(p.x-p0.x, p.y-p0.y);
102 if (p0.x < -1 || p0.y < -1 || p0.x>=src.width() || p0.y>=src.height())
107 pixel<F,devicen_layout_t<num_channels<SrcView>::value> > mp(0); // suboptimal
108 typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y);
114 // the top-left corner pixel
116 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp);
118 else if (p0.y+1<src.height())
120 // on the first column, but not the top-left nor bottom-left corner pixel
121 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], (1-frac.y),mp);
123 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.y ,mp);
127 // the bottom-left corner pixel
128 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp);
131 else if (p0.x+1<src.width())
135 // on the first row, but not the top-left nor top-right corner pixel
137 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp);
138 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp);
140 else if (p0.y+1<src.height())
142 // most common case - inside the image, not on the frist nor last row/column
143 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)*(1-frac.y),mp);
144 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);
146 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)* frac.y ,mp);
147 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x * frac.y ,mp);
151 // on the last row, but not the bottom-left nor bottom-right corner pixel
152 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp);
153 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp);
160 // the top-right corner pixel
162 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp);
164 else if (p0.y+1<src.height())
166 // on the last column, but not the top-right nor bottom-right corner pixel
167 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.y),mp);
169 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, frac.y ,mp);
173 // the bottom-right corner pixel
174 detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp);
178 // Convert from floating point average value to the source type
180 cast_pixel(mp,src_result);
182 color_convert(src_result, result);
186 }} // namespace boost::gil