scaling.hpp 4.2 KB

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