libs/gil/example/resize.cpp というのを見つけて、これはもしや?と思ったが、boost/gil/extension/numeric/* が、ごっそりと抜け落ちていてコンパイルできない…。どこにあるんだべーと探したら、GIL本家のダウンロードページにあった(現在、ここからサルベージするしかない)。
さっそく bicubic が落ちていないか探したが、bilinear までしか実装されていないようだ。チャレンジしようと思ったが、gil をよく知らないので苦労した。チュートリアルの日本語訳があって、非常に助かりました。
という訳で、csampler.hpp です。
/*************************************************************************************************/
#ifndef GIL_CSAMPLER_HPP
#define GIL_CSAMPLER_HPP
#include "../../extension/dynamic_image/dynamic_image_all.hpp"
#include "pixel_numeric_operations.hpp"
#include "sampler.hpp"
namespace boost { namespace gil {
struct truncate_channel_fn {
template <typename SrcChannel, typename DstChannel>
void operator()(const SrcChannel& src, DstChannel& dst) {
typedef typename channel_traits<DstChannel>::value_type dst_value_t;
if(std::numeric_limits<dst_value_t>::max() <= src)
dst = std::numeric_limits<dst_value_t>::max();
else if( src < 0 ) dst = dst_value_t();
else dst = dst_value_t(src);
}
};
template <typename SrcPixel, typename DstPixel>
void truncate_pixel(const SrcPixel& src, DstPixel& dst) {
static_for_each(src,dst,truncate_channel_fn());
}
/// \brief A sampler that sets the destination pixel as the bicubic interpolation of the four closest pixels from the source.
/// If outside the bounds, it doesn't change the destination
/// \ingroup ImageAlgorithms
struct bicubic_sampler {};
template <typename DstP, typename SrcView, typename F>
bool sample(bicubic_sampler, const SrcView& src, const point2<F>& p, DstP& result) {
typedef typename SrcView::value_type SrcP;
point2<int> p0(ifloor(p)); // the closest integer coordinate top left from p
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);
for( int y = -1; y < 3; ++y ) {
for( int x = -1; x < 3; ++x ) {
point2<F> frac(std::abs(p.x-static_cast<F>(p0.x+x)),std::abs(p.y-static_cast<F>(p0.y+y)));
F wx, wy;
if( frac.x < static_cast<F>(1) ) wx = (frac.x - 1) * (frac.x * frac.x - frac.x - 1);
else wx = (1 - frac.x) * (frac.x - 2) * (frac.x - 2);
if( frac.y < static_cast<F>(1) ) wy = (frac.y - 1) * (frac.y * frac.y - frac.y - 1);
else wy = (1 - frac.y) * (frac.y - 2) * (frac.y - 2);
int offx = ( p0.x+x < 0 || p0.x+x>=src.width() ) ? 0 : x;
int offy = ( p0.y+y < 0 || p0.y+y>=src.height() ) ? 0 : y;
detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()( loc(offx,offy), wx * wy, mp );
}
}
// Convert from floating point average value to the source type
SrcP src_result;
truncate_pixel(mp,src_result);
color_convert(src_result, result);
return true;
}
} } // namespace boost::gil
#endif
お試しコードは、resize.cpp をちょいと改造するだけ。せっかくの bicubic なので拡大してみました。
#include <boost/gil/image.hpp>
#include <boost/gil/typedefs.hpp>
#include <boost/gil/extension/io/jpeg_io.hpp>
#include <boost/gil/extension/numeric/sampler.hpp>
#include <boost/gil/extension/numeric/csampler.hpp>
#include <boost/gil/extension/numeric/resample.hpp>
int main() {
using namespace boost::gil;
rgb8_image_t img;
jpeg_read_image("test.jpg",img);
// test resize_view
// Scale the image to 100x100 pixels using bilinear resampling
rgb8_image_t square100x100(600,600);
resize_view(const_view(img), view(square100x100), bicubic_sampler());
jpeg_write_view("out-resize.jpg",const_view(square100x100));
return 0;
}
0 件のコメント:
コメントを投稿