/* Copyright 2005-2007 Adobe Systems Incorporated Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). */ /*************************************************************************************************/ #ifndef BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP #define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP #include #include //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief Nearest-neighbor and bilinear image samplers. /// NOTE: The code is for example use only. It is not optimized for performance /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated /// \date 2005-2007 \n /// //////////////////////////////////////////////////////////////////////////////////////// namespace boost { namespace gil { /////////////////////////////////////////////////////////////////////////// //// //// resample_pixels: set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view //// /////////////////////////////////////////////////////////////////////////// /* template concept SamplerConcept { template // Models PointNDConcept, where S_COORDS::num_dimensions == SrcView::num_dimensions bool sample(const Sampler& s, const SrcView& src, const S_COORDS& p, DstP result); }; */ /// \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 /// \ingroup ImageAlgorithms struct nearest_neighbor_sampler {}; template bool sample(nearest_neighbor_sampler, const SrcView& src, const point2& p, DstP& result) { typename SrcView::point_t center(iround(p)); if (center.x>=0 && center.y>=0 && center.x void operator()(const SrcChannel& src, DstChannel& dst) { typedef typename channel_traits::value_type dst_value_t; dst = dst_value_t(src); } }; template void cast_pixel(const SrcPixel& src, DstPixel& dst) { static_for_each(src,dst,cast_channel_fn()); } namespace detail { template struct add_dst_mul_src_channel { Weight _w; add_dst_mul_src_channel(Weight w) : _w(w) {} template void operator()(const SrcChannel& src, DstChannel& dst) const { dst += DstChannel(src*_w); } }; // dst += DST_TYPE(src * w) template struct add_dst_mul_src { void operator()(const SrcP& src, Weight weight, DstP& dst) const { static_for_each(src,dst, add_dst_mul_src_channel(weight)); // pixel_assigns_t()( // pixel_plus_t()( // pixel_multiplies_scalar_t()(src,weight), // dst), // dst); } }; } // namespace detail /// \brief A sampler that sets the destination pixel as the bilinear interpolation of the four closest pixels from the source. /// If outside the bounds, it doesn't change the destination /// \ingroup ImageAlgorithms struct bilinear_sampler {}; template bool sample(bilinear_sampler, const SrcView& src, const point2& p, DstP& result) { typedef typename SrcView::value_type SrcP; point2 p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p point2 frac(p.x-p0.x, p.y-p0.y); if (p0.x < -1 || p0.y < -1 || p0.x>=src.width() || p0.y>=src.height()) { return false; } pixel::value> > mp(0); // suboptimal typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y); if (p0.x == -1) { if (p0.y == -1) { // the top-left corner pixel ++loc.y(); detail::add_dst_mul_src::value> > >()(loc.x()[1], 1 ,mp); } else if (p0.y+1::value> > >()(loc.x()[1], (1-frac.y),mp); ++loc.y(); detail::add_dst_mul_src::value> > >()(loc.x()[1], frac.y ,mp); } else { // the bottom-left corner pixel detail::add_dst_mul_src::value> > >()(loc.x()[1], 1 ,mp); } } else if (p0.x+1::value> > >()(*loc, (1-frac.x) ,mp); detail::add_dst_mul_src::value> > >()(loc.x()[1], frac.x ,mp); } else if (p0.y+1::value> > >()(*loc, (1-frac.x)*(1-frac.y),mp); detail::add_dst_mul_src::value> > >()(loc.x()[1], frac.x *(1-frac.y),mp); ++loc.y(); detail::add_dst_mul_src::value> > >()(*loc, (1-frac.x)* frac.y ,mp); detail::add_dst_mul_src::value> > >()(loc.x()[1], frac.x * frac.y ,mp); } else { // on the last row, but not the bottom-left nor bottom-right corner pixel detail::add_dst_mul_src::value> > >()(*loc, (1-frac.x) ,mp); detail::add_dst_mul_src::value> > >()(loc.x()[1], frac.x ,mp); } } else { if (p0.y == -1) { // the top-right corner pixel ++loc.y(); detail::add_dst_mul_src::value> > >()(*loc, 1 ,mp); } else if (p0.y+1::value> > >()(*loc, (1-frac.y),mp); ++loc.y(); detail::add_dst_mul_src::value> > >()(*loc, frac.y ,mp); } else { // the bottom-right corner pixel detail::add_dst_mul_src::value> > >()(*loc, 1 ,mp); } } // Convert from floating point average value to the source type SrcP src_result; cast_pixel(mp,src_result); color_convert(src_result, result); return true; } } // namespace gil } // namespace boost #endif // BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP