libs/boost-gil-extension/boost/gil/extension/numeric/sampler.hpp

137 lines
6.0 KiB
C++
Raw Normal View History

2017-01-10 04:08:49 +00:00
/*
Copyright 2005-2007 Adobe Systems Incorporated
Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
or a copy at http://opensource.adobe.com/licenses.html)
*/
/*************************************************************************************************/
#ifndef GIL_SAMPLER_HPP
#define GIL_SAMPLER_HPP
#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
#include "pixel_numeric_operations.hpp"
////////////////////////////////////////////////////////////////////////////////////////
/// \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 October 30, 2006
///
////////////////////////////////////////////////////////////////////////////////////////
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 <typename Sampler>
concept SamplerConcept {
template <typename DstP, // Models PixelConcept
typename SrcView, // Models RandomAccessNDImageViewConcept
typename S_COORDS> // 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 <typename DstP, typename SrcView, typename F>
bool sample(nearest_neighbor_sampler, const SrcView& src, const point2<F>& p, DstP& result) {
point2<int> 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;
}
template <typename SrcPixel, typename DstPixel>
void cast_pixel(const SrcPixel& src, DstPixel& dst) {
static_for_each(src,dst,channel_assigns_t<typename channel_type<SrcPixel>::type,
typename channel_type<DstPixel>::type>());
}
namespace detail {
template <typename Weight>
struct add_dst_mul_src_channel {
Weight _w;
add_dst_mul_src_channel(Weight w) : _w(w) {}
template <typename SrcChannel, typename DstChannel>
void operator()(const SrcChannel& src, DstChannel& dst) const {
dst += DstChannel(src*_w);
}
};
// dst += DST_TYPE(src * w)
template <typename SrcP,typename Weight,typename DstP>
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>(weight));
// pixel_assigns_t<DstP,DstP&>()(
// pixel_plus_t<DstP,DstP,DstP>()(
// pixel_multiplies_scalar_t<SrcP,Weight,DstP>()(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 <typename DstP, typename SrcView, typename F>
bool sample(bilinear_sampler, const SrcView& src, const point2<F>& p, DstP& result) {
typedef typename SrcView::value_type SrcP;
point2<std::ptrdiff_t> p0(ifloor(p)); // the closest integer coordinate top left from p
point2<F> frac(p.x-p0.x, p.y-p0.y);
if (p0.x < 0 || p0.y < 0 || p0.x>=src.width() || p0.y>=src.height()) return false;
pixel<F,devicen_layout_t<num_channels<SrcView>::value> > mp(0); // suboptimal
typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y);
if (p0.x+1<src.width()) {
if (p0.y+1<src.height()) {
// most common case - inside the image, not on the last row or column
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)*(1-frac.y),mp);
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);
++loc.y();
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)* frac.y ,mp);
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x * frac.y ,mp);
} else {
// on the last row, but not the bottom-right corner pixel
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x),mp);
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp);
}
} else {
if (p0.y+1<src.height()) {
// on the last column, but not the bottom-right corner pixel
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.y),mp);
++loc.y();
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, frac.y ,mp);
} else {
// the bottom-right corner pixel
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc,1,mp);
}
}
// pixel_assigns_t<pixel<F,devicen_layout_t<num_channels<SrcView>::value> >,DstP&>()(mp,result);
cast_pixel(mp,result);
return true;
}
} } // namespace boost::gil
#endif