Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / numeric / sampler.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
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 #ifndef BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
9 #define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
10
11 #include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
12 #include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
13
14 namespace boost { namespace gil {
15
16 // Nearest-neighbor and bilinear image samplers.
17 // NOTE: The code is for example use only. It is not optimized for performance
18
19 ///////////////////////////////////////////////////////////////////////////
20 ////
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
22 ////
23 ///////////////////////////////////////////////////////////////////////////
24 /*
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);
31 };
32 */
33
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 {};
37
38 template <typename DstP, typename SrcView, typename F>
39 bool sample(nearest_neighbor_sampler, SrcView const& src, point<F> const& p, DstP& result)
40 {
41     typename SrcView::point_t center(iround(p));
42     if (center.x >= 0 && center.y >= 0 && center.x < src.width() && center.y < src.height())
43     {
44         result=src(center.x,center.y);
45         return true;
46     }
47     return false;
48 }
49
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);
55     }
56 };
57
58 template <typename SrcPixel, typename DstPixel>
59 void cast_pixel(const SrcPixel& src, DstPixel& dst) {
60     static_for_each(src,dst,cast_channel_fn());
61 }
62
63 namespace detail {
64
65 template <typename Weight>
66 struct add_dst_mul_src_channel {
67     Weight _w;
68     add_dst_mul_src_channel(Weight w) : _w(w) {}
69
70     template <typename SrcChannel, typename DstChannel>
71     void operator()(const SrcChannel& src, DstChannel& dst) const {
72         dst += DstChannel(src*_w);
73     }
74 };
75
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),
84 //                dst),
85 //            dst);
86     }
87 };
88 } // namespace detail
89
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 {};
94
95 template <typename DstP, typename SrcView, typename F>
96 bool sample(bilinear_sampler, SrcView const& src, point<F> const& p, DstP& result)
97 {
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);
101
102     if (p0.x < -1 || p0.y < -1 || p0.x>=src.width() || p0.y>=src.height())
103     {
104         return false;
105     }
106
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);
109
110         if (p0.x == -1)
111     {
112                 if (p0.y == -1)
113         {
114                     // the top-left corner pixel
115                         ++loc.y();
116                         detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1],  1        ,mp);
117                 }
118         else if (p0.y+1<src.height())
119         {
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);
122                         ++loc.y();
123                         detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1],    frac.y ,mp);
124                 }
125         else
126         {
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);
129                 }
130         }
131     else if (p0.x+1<src.width())
132     {
133                 if (p0.y == -1)
134         {
135                     // on the first row, but not the top-left nor top-right corner pixel
136                         ++loc.y();
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);
139                 }
140         else if (p0.y+1<src.height())
141         {
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);
145                         ++loc.y();
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);
148                 }
149         else
150         {
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);
154                 }
155         }
156     else
157     {
158         if (p0.y == -1)
159         {
160             // the top-right corner pixel
161             ++loc.y();
162             detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc,  1        ,mp);
163         }
164         else if (p0.y+1<src.height())
165         {
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);
168                         ++loc.y();
169                         detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc,    frac.y ,mp);
170                 }
171         else
172         {
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);
175                 }
176         }
177
178         // Convert from floating point average value to the source type
179         SrcP src_result;
180         cast_pixel(mp,src_result);
181
182         color_convert(src_result, result);
183         return true;
184 }
185
186 }}  // namespace boost::gil
187
188 #endif