137 lines
6.0 KiB
C++
Executable File
137 lines
6.0 KiB
C++
Executable File
/*
|
|
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
|