// // Copyright 2005-2007 Adobe Systems Incorporated // // Distributed under 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 namespace boost { namespace gil { // Nearest-neighbor and bilinear image samplers. // NOTE: The code is for example use only. It is not optimized for performance /////////////////////////////////////////////////////////////////////////// //// //// 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, SrcView const& src, point const& p, DstP& result) { typename SrcView::point_t center(iround(p)); if (center.x >= 0 && center.y >= 0 && center.x < src.width() && center.y < src.height()) { result=src(center.x,center.y); return true; } return false; } struct cast_channel_fn { template void operator()(const SrcChannel& src, DstChannel& dst) { using dst_value_t = typename channel_traits::value_type; 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, SrcView const& src, point const& p, DstP& result) { using SrcP = typename SrcView::value_type; point_t p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p point 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 boost::gil #endif