Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / image_processing / scaling.hpp
1 //
2 // Copyright 2019 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
3 //
4 // Use, modification and distribution are subject to the Boost Software License,
5 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_GIL_IMAGE_PROCESSING_SCALING_HPP
9 #define BOOST_GIL_IMAGE_PROCESSING_SCALING_HPP
10
11 #include <boost/gil/image_view.hpp>
12 #include <boost/gil/rgb.hpp>
13 #include <boost/gil/pixel.hpp>
14 #include <boost/gil/image_processing/numeric.hpp>
15
16 namespace boost { namespace gil {
17
18 /// \defgroup ScalingAlgorithms
19 /// \brief Algorthims suitable for rescaling
20 ///
21 /// These algorithms are used to improve image quality after image resizing is made.
22 ///
23 /// \defgroup DownScalingAlgorithms
24 /// \ingroup ScalingAlgorithms
25 /// \brief Algorthims suitable for downscaling
26 ///
27 /// These algorithms provide best results when used for downscaling. Using for upscaling will
28 /// probably provide less than good results.
29 ///
30 /// \brief a single step of lanczos downscaling
31 /// \ingroup DownScalingAlgorithms
32 ///
33 /// Use this algorithm to scale down source image into a smaller image with reasonable quality.
34 /// Do note that having a look at the output once is a good idea, since it might have ringing
35 /// artifacts.
36 template <typename ImageView>
37 void lanczos_at(
38     ImageView input_view,
39     ImageView output_view,
40     typename ImageView::x_coord_t source_x,
41     typename ImageView::y_coord_t source_y,
42     typename ImageView::x_coord_t target_x,
43     typename ImageView::y_coord_t target_y,
44     std::ptrdiff_t a)
45 {
46     using x_coord_t = typename ImageView::x_coord_t;
47     using y_coord_t = typename ImageView::y_coord_t;
48     using pixel_t = typename std::remove_reference<decltype(std::declval<ImageView>()(0, 0))>::type;
49
50     // C++11 doesn't allow auto in lambdas
51     using channel_t = typename std::remove_reference
52         <
53             decltype(std::declval<pixel_t>().at(std::integral_constant<int, 0>{}))
54         >::type;
55
56     pixel_t result_pixel;
57     static_transform(result_pixel, result_pixel, [](channel_t) {
58         return static_cast<channel_t>(0);
59     });
60     auto x_zero = static_cast<x_coord_t>(0);
61     auto x_one = static_cast<x_coord_t>(1);
62     auto y_zero = static_cast<y_coord_t>(0);
63     auto y_one = static_cast<y_coord_t>(1);
64
65     for (y_coord_t y_i = (std::max)(source_y - static_cast<y_coord_t>(a) + y_one, y_zero);
66          y_i <= (std::min)(source_y + static_cast<y_coord_t>(a), input_view.height() - y_one);
67          ++y_i)
68     {
69         for (x_coord_t x_i = (std::max)(source_x - static_cast<x_coord_t>(a) + x_one, x_zero);
70              x_i <= (std::min)(source_x + static_cast<x_coord_t>(a), input_view.width() - x_one);
71              ++x_i)
72         {
73             double lanczos_response = lanczos(source_x - x_i, a) * lanczos(source_y - y_i, a);
74             auto op = [lanczos_response](channel_t prev, channel_t next)
75             {
76                 return static_cast<channel_t>(prev + next * lanczos_response);
77             };
78             static_transform(result_pixel, input_view(source_x, source_y), result_pixel, op);
79         }
80     }
81
82     output_view(target_x, target_y) = result_pixel;
83 }
84
85 /// \brief Complete Lanczos algorithm
86 /// \ingroup DownScalingAlgorithms
87 ///
88 /// This algorithm does full pass over resulting image and convolves pixels from
89 /// original image. Do note that it might be a good idea to have a look at test
90 /// output as there might be ringing artifacts.
91 /// Based on wikipedia article:
92 /// https://en.wikipedia.org/wiki/Lanczos_resampling
93 /// with standardinzed cardinal sin (sinc)
94 template <typename ImageView>
95 void scale_lanczos(ImageView input_view, ImageView output_view, std::ptrdiff_t a)
96 {
97     double scale_x = (static_cast<double>(output_view.width()))
98                      / static_cast<double>(input_view.width());
99     double scale_y = (static_cast<double>(output_view.height()))
100                      / static_cast<double>(input_view.height());
101
102     using x_coord_t = typename ImageView::x_coord_t;
103     using y_coord_t = typename ImageView::y_coord_t;
104     for (y_coord_t y = 0; y < output_view.height(); ++y)
105     {
106         for (x_coord_t x = 0; x < output_view.width(); ++x)
107         {
108             lanczos_at(input_view, output_view, x / scale_x, y / scale_y, x, y, a);
109         }
110     }
111 }
112
113 }} // namespace boost::gil
114
115 #endif