116 lines
4.2 KiB
C++
116 lines
4.2 KiB
C++
|
//
|
||
|
// Copyright 2019 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
|
||
|
//
|
||
|
// Use, modification and distribution are subject to 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_IMAGE_PROCESSING_SCALING_HPP
|
||
|
#define BOOST_GIL_IMAGE_PROCESSING_SCALING_HPP
|
||
|
|
||
|
#include <boost/gil/image_view.hpp>
|
||
|
#include <boost/gil/rgb.hpp>
|
||
|
#include <boost/gil/pixel.hpp>
|
||
|
#include <boost/gil/image_processing/numeric.hpp>
|
||
|
|
||
|
namespace boost { namespace gil {
|
||
|
|
||
|
/// \defgroup ScalingAlgorithms
|
||
|
/// \brief Algorthims suitable for rescaling
|
||
|
///
|
||
|
/// These algorithms are used to improve image quality after image resizing is made.
|
||
|
///
|
||
|
/// \defgroup DownScalingAlgorithms
|
||
|
/// \ingroup ScalingAlgorithms
|
||
|
/// \brief Algorthims suitable for downscaling
|
||
|
///
|
||
|
/// These algorithms provide best results when used for downscaling. Using for upscaling will
|
||
|
/// probably provide less than good results.
|
||
|
///
|
||
|
/// \brief a single step of lanczos downscaling
|
||
|
/// \ingroup DownScalingAlgorithms
|
||
|
///
|
||
|
/// Use this algorithm to scale down source image into a smaller image with reasonable quality.
|
||
|
/// Do note that having a look at the output once is a good idea, since it might have ringing
|
||
|
/// artifacts.
|
||
|
template <typename ImageView>
|
||
|
void lanczos_at(
|
||
|
ImageView input_view,
|
||
|
ImageView output_view,
|
||
|
typename ImageView::x_coord_t source_x,
|
||
|
typename ImageView::y_coord_t source_y,
|
||
|
typename ImageView::x_coord_t target_x,
|
||
|
typename ImageView::y_coord_t target_y,
|
||
|
std::ptrdiff_t a)
|
||
|
{
|
||
|
using x_coord_t = typename ImageView::x_coord_t;
|
||
|
using y_coord_t = typename ImageView::y_coord_t;
|
||
|
using pixel_t = typename std::remove_reference<decltype(std::declval<ImageView>()(0, 0))>::type;
|
||
|
|
||
|
// C++11 doesn't allow auto in lambdas
|
||
|
using channel_t = typename std::remove_reference
|
||
|
<
|
||
|
decltype(std::declval<pixel_t>().at(std::integral_constant<int, 0>{}))
|
||
|
>::type;
|
||
|
|
||
|
pixel_t result_pixel;
|
||
|
static_transform(result_pixel, result_pixel, [](channel_t) {
|
||
|
return static_cast<channel_t>(0);
|
||
|
});
|
||
|
auto x_zero = static_cast<x_coord_t>(0);
|
||
|
auto x_one = static_cast<x_coord_t>(1);
|
||
|
auto y_zero = static_cast<y_coord_t>(0);
|
||
|
auto y_one = static_cast<y_coord_t>(1);
|
||
|
|
||
|
for (y_coord_t y_i = (std::max)(source_y - static_cast<y_coord_t>(a) + y_one, y_zero);
|
||
|
y_i <= (std::min)(source_y + static_cast<y_coord_t>(a), input_view.height() - y_one);
|
||
|
++y_i)
|
||
|
{
|
||
|
for (x_coord_t x_i = (std::max)(source_x - static_cast<x_coord_t>(a) + x_one, x_zero);
|
||
|
x_i <= (std::min)(source_x + static_cast<x_coord_t>(a), input_view.width() - x_one);
|
||
|
++x_i)
|
||
|
{
|
||
|
double lanczos_response = lanczos(source_x - x_i, a) * lanczos(source_y - y_i, a);
|
||
|
auto op = [lanczos_response](channel_t prev, channel_t next)
|
||
|
{
|
||
|
return static_cast<channel_t>(prev + next * lanczos_response);
|
||
|
};
|
||
|
static_transform(result_pixel, input_view(source_x, source_y), result_pixel, op);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
output_view(target_x, target_y) = result_pixel;
|
||
|
}
|
||
|
|
||
|
/// \brief Complete Lanczos algorithm
|
||
|
/// \ingroup DownScalingAlgorithms
|
||
|
///
|
||
|
/// This algorithm does full pass over resulting image and convolves pixels from
|
||
|
/// original image. Do note that it might be a good idea to have a look at test
|
||
|
/// output as there might be ringing artifacts.
|
||
|
/// Based on wikipedia article:
|
||
|
/// https://en.wikipedia.org/wiki/Lanczos_resampling
|
||
|
/// with standardinzed cardinal sin (sinc)
|
||
|
template <typename ImageView>
|
||
|
void scale_lanczos(ImageView input_view, ImageView output_view, std::ptrdiff_t a)
|
||
|
{
|
||
|
double scale_x = (static_cast<double>(output_view.width()))
|
||
|
/ static_cast<double>(input_view.width());
|
||
|
double scale_y = (static_cast<double>(output_view.height()))
|
||
|
/ static_cast<double>(input_view.height());
|
||
|
|
||
|
using x_coord_t = typename ImageView::x_coord_t;
|
||
|
using y_coord_t = typename ImageView::y_coord_t;
|
||
|
for (y_coord_t y = 0; y < output_view.height(); ++y)
|
||
|
{
|
||
|
for (x_coord_t x = 0; x < output_view.width(); ++x)
|
||
|
{
|
||
|
lanczos_at(input_view, output_view, x / scale_x, y / scale_y, x, y, a);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}} // namespace boost::gil
|
||
|
|
||
|
#endif
|