やったね!
余談
翻訳をすることは勉強にもなって非常にいいですし皆さんにもぜひやって欲しいのですが、
その分、なんというか、日本の中へと篭ってしまうことにも繋がっている気がします。
英語に臆することなく積極的にアウトプットできるよう、自分自身の心構えをもう少しきちんとしなければならんですね。
ちょっと映像関係でてきました
#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/io/jpeg_io.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace boost::gil;
struct change_brightness {
public:
change_brightness(): weight_(1.0) {};
explicit change_brightness(float weight): weight_(weight) {};
template<typename Pixel>
Pixel operator()(Pixel src) {
typedef typename channel_type<Pixel>::type channel_type;
Pixel dst;
for(int c=0; c<num_channels<Pixel>::value; ++c) {
dst[c] = cv::saturate_cast<channel_type>(
static_cast<float>(src[c] * weight_));
}
return dst;
}
private:
float weight_;
};
struct change_brightness_locator {
public:
change_brightness_locator(): weight_(1.0) {};
explicit change_brightness_locator(float weight): weight_(weight) {};
template<typename Locator>
typename Locator::value_type operator()(Locator loc) {
typedef typename Locator::value_type pixel_type;
typedef typename channel_type<Locator>::type channel_type;
pixel_type src = loc(0, 0);
pixel_type dst;
for(int c=0; c<num_channels<Locator>::value; ++c) {
dst[c] = cv::saturate_cast<channel_type>(
static_cast<float>(src[c]) * weight_);
}
return dst;
}
private:
float weight_;
};
template<typename Locator>
struct x_gradient_functor {
public:
explicit x_gradient_functor(Locator loc)
: left_(loc.cache_location(-1, 0)),
right_(loc.cache_location(1, 0)) {};
typename Locator::value_type operator()(Locator loc) {
typedef typename Locator::value_type pixel_type;
typedef typename channel_type<Locator>::type channel_type;
pixel_type src_left = loc[left_];
pixel_type src_right = loc[right_];
pixel_type dst;
for(int c=0; c<num_channels<Locator>::value; ++c)
dst[c] = (src_left[c] - src_right[c])/2;
return dst;
}
private:
typename Locator::cached_location_t left_;
typename Locator::cached_location_t right_;
};
template <typename SrcView, typename DstView>
void x_gradient(const SrcView& src, const DstView& dst) {
assert(src.dimensions() == dst.dimensions());
transform_pixel_positions(
subimage_view(src, 1, 0, src.width()-2, src.height()),
subimage_view(dst, 1, 0, src.width()-2, src.height()),
x_gradient_functor<typename SrcView::locator>(src.xy_at(0, 0)));
}
int main() {
const char* filename = "lena.jpg";
rgb8_image_t src_image;
jpeg_read_image(filename, src_image);
rgb8_image_t dst_image(src_image.dimensions());
transform_pixels(
const_view(src_image),
view(dst_image),
change_brightness(1.5));
jpeg_write_view("result_normal.jpg", view(dst_image));
transform_pixel_positions(
const_view(src_image),
view(dst_image),
change_brightness_locator(2.0));
jpeg_write_view("result_locator.jpg", view(dst_image));
x_gradient(const_view(src_image), view(dst_image));
jpeg_write_view("result_gradient.jpg", view(dst_image));
return 0;
}
![]() |
| 左から、元画像, change_brightness, change_brightness_locator, x_gradientの結果 |
typedef typename channel_type<Pixel>::type channel_type;channel_type<T>::typeで実際に使われているチャネルの型を取得できます。Tにはピクセル、ロケータ、ビューのどれを指定しても構いません。今回の場合ですと8bitのチャネルを指定しているので、型にはunsigned charが入ります。
num_channels<Pixel>::valueピクセルを構成しているチャネルの数を取得できます。この場合ですと色空間がRGBなので値には3が入ります。この値はコンパイル時に決定されるので、最適化を用いることでループ展開が行われ、速度的なオーバーヘッドはありません。
typedef typename Locator::value_type pixel_type;ロケータが返すピクセルの型を取得できます。この場合ですとrgb8_pixel_tが入ります。
pixel_type src = loc(0, 0);()演算子によって現在のピクセル値を取得しています。他にも*演算子でイテレータっぽくアクセスすることもできます。
explicit x_gradient_functor(Locator loc)
: left_(loc.cache_location(-1, 0)),
right_(loc.cache_location(1, 0)) {};ロケータの変動値をキャッシュしておくことで、高速化を図ります。Locator::cached_location_tによってロケータのキャッシュ型を取得します。キャッシュを使ったアクセスには[]演算子を用います。subimage_view(src, 1, 0, src.width()-2, src.height())subimage_view()によって画像の領域を切り出しています。これはアダプタで、実際の評価は遅延的に行われます。