filter.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //
  2. // Copyright 2019 Miral Shah <miralshah2211@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_FILTER_HPP
  9. #define BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP
  10. #include <boost/gil/extension/numeric/algorithm.hpp>
  11. #include <boost/gil/extension/numeric/kernel.hpp>
  12. #include <boost/gil/extension/numeric/convolve.hpp>
  13. #include <boost/gil/image.hpp>
  14. #include <boost/gil/image_view.hpp>
  15. #include <cstddef>
  16. #include <vector>
  17. namespace boost { namespace gil {
  18. template <typename SrcView, typename DstView>
  19. void box_filter(
  20. SrcView const& src_view,
  21. DstView const& dst_view,
  22. std::size_t kernel_size,
  23. long int anchor = -1,
  24. bool normalize=true,
  25. boundary_option option = boundary_option::extend_zero
  26. )
  27. {
  28. gil_function_requires<ImageViewConcept<SrcView>>();
  29. gil_function_requires<MutableImageViewConcept<DstView>>();
  30. static_assert(color_spaces_are_compatible
  31. <
  32. typename color_space_type<SrcView>::type,
  33. typename color_space_type<DstView>::type
  34. >::value, "Source and destination views must have pixels with the same color space");
  35. std::vector<float> kernel_values;
  36. if (normalize) { kernel_values.resize(kernel_size, 1.0f / float(kernel_size)); }
  37. else { kernel_values.resize(kernel_size, 1.0f); }
  38. if (anchor == -1) anchor = static_cast<int>(kernel_size / 2);
  39. kernel_1d<float> kernel(kernel_values.begin(), kernel_size, anchor);
  40. detail::convolve_1d
  41. <
  42. pixel<float, typename SrcView::value_type::layout_t>
  43. >(src_view, kernel, dst_view, option);
  44. }
  45. template <typename SrcView, typename DstView>
  46. void blur(
  47. SrcView const& src_view,
  48. DstView const& dst_view,
  49. std::size_t kernel_size,
  50. long int anchor = -1,
  51. boundary_option option = boundary_option::extend_zero
  52. )
  53. {
  54. box_filter(src_view, dst_view, kernel_size, anchor, true, option);
  55. }
  56. namespace detail
  57. {
  58. template <typename SrcView, typename DstView>
  59. void filter_median_impl(SrcView const& src_view, DstView const& dst_view, std::size_t kernel_size)
  60. {
  61. std::size_t half_kernel_size = kernel_size / 2;
  62. // deciding output channel type and creating functor
  63. using src_channel_t = typename channel_type<SrcView>::type;
  64. std::vector<src_channel_t> values;
  65. values.reserve(kernel_size * kernel_size);
  66. for (std::ptrdiff_t y = 0; y < src_view.height(); y++)
  67. {
  68. typename DstView::x_iterator dst_it = dst_view.row_begin(y);
  69. for (std::ptrdiff_t x = 0; x < src_view.width(); x++)
  70. {
  71. auto sub_view = subimage_view(
  72. src_view,
  73. x - half_kernel_size, y - half_kernel_size,
  74. kernel_size,
  75. kernel_size
  76. );
  77. values.assign(sub_view.begin(), sub_view.end());
  78. std::nth_element(values.begin(), values.begin() + (values.size() / 2), values.end());
  79. dst_it[x] = values[values.size() / 2];
  80. }
  81. }
  82. }
  83. } // namespace detail
  84. template <typename SrcView, typename DstView>
  85. void median_filter(SrcView const& src_view, DstView const& dst_view, std::size_t kernel_size)
  86. {
  87. static_assert(color_spaces_are_compatible
  88. <
  89. typename color_space_type<SrcView>::type,
  90. typename color_space_type<DstView>::type
  91. >::value, "Source and destination views must have pixels with the same color space");
  92. std::size_t half_kernel_size = kernel_size / 2;
  93. auto extended_img = extend_boundary(
  94. src_view,
  95. half_kernel_size,
  96. boundary_option::extend_constant
  97. );
  98. auto extended_view = subimage_view(
  99. view(extended_img),
  100. half_kernel_size,
  101. half_kernel_size,
  102. src_view.width(),
  103. src_view.height()
  104. );
  105. for (std::size_t channel = 0; channel < extended_view.num_channels(); channel++)
  106. {
  107. detail::filter_median_impl(
  108. nth_channel_view(extended_view, channel),
  109. nth_channel_view(dst_view, channel),
  110. kernel_size
  111. );
  112. }
  113. }
  114. }} //namespace boost::gil
  115. #endif // !BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP