histogram_equalization.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. //
  2. // Copyright 2020 Debabrata Mandal <mandaldebabrata123@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_HISTOGRAM_EQUALIZATION_HPP
  9. #define BOOST_GIL_IMAGE_PROCESSING_HISTOGRAM_EQUALIZATION_HPP
  10. #include <boost/gil/histogram.hpp>
  11. #include <boost/gil/image.hpp>
  12. #include <cmath>
  13. #include <map>
  14. #include <vector>
  15. namespace boost { namespace gil {
  16. /////////////////////////////////////////
  17. /// Histogram Equalization(HE)
  18. /////////////////////////////////////////
  19. /// \defgroup HE HE
  20. /// \brief Contains implementation and description of the algorithm used to compute
  21. /// global histogram equalization of input images.
  22. ///
  23. /// Algorithm :-
  24. /// 1. If histogram A is to be equalized compute the cumulative histogram of A.
  25. /// 2. Let CFD(A) refer to the cumulative histogram of A
  26. /// 3. For a uniform histogram A', CDF(A') = A'
  27. /// 4. We need to transfrom A to A' such that
  28. /// 5. CDF(A') = CDF(A) => A' = CDF(A)
  29. /// 6. Hence the pixel transform , px => histogram_of_ith_channel[px].
  30. ///
  31. /// \fn histogram_equalization
  32. /// \ingroup HE
  33. /// \tparam SrcKeyType Key Type of input histogram
  34. /// @param src_hist INPUT Input source histogram
  35. /// \brief Overload for histogram equalization algorithm, takes in a single source histogram
  36. /// and returns the color map used for histogram equalization.
  37. ///
  38. template <typename SrcKeyType>
  39. auto histogram_equalization(histogram<SrcKeyType> const& src_hist)
  40. -> std::map<SrcKeyType, SrcKeyType>
  41. {
  42. histogram<SrcKeyType> dst_hist;
  43. return histogram_equalization(src_hist, dst_hist);
  44. }
  45. /// \overload histogram_equalization
  46. /// \ingroup HE
  47. /// \tparam SrcKeyType Key Type of input histogram
  48. /// \tparam DstKeyType Key Type of output histogram
  49. /// @param src_hist INPUT source histogram
  50. /// @param dst_hist OUTPUT Output histogram
  51. /// \brief Overload for histogram equalization algorithm, takes in both source histogram &
  52. /// destination histogram and returns the color map used for histogram equalization
  53. /// as well as transforming the destination histogram.
  54. ///
  55. template <typename SrcKeyType, typename DstKeyType>
  56. auto histogram_equalization(histogram<SrcKeyType> const& src_hist, histogram<DstKeyType>& dst_hist)
  57. -> std::map<SrcKeyType, DstKeyType>
  58. {
  59. static_assert(
  60. std::is_integral<SrcKeyType>::value &&
  61. std::is_integral<DstKeyType>::value,
  62. "Source and destination histogram types are not appropriate");
  63. using value_t = typename histogram<SrcKeyType>::value_type;
  64. dst_hist.clear();
  65. double sum = src_hist.sum();
  66. SrcKeyType min_key = (std::numeric_limits<DstKeyType>::min)();
  67. SrcKeyType max_key = (std::numeric_limits<DstKeyType>::max)();
  68. auto cumltv_srchist = cumulative_histogram(src_hist);
  69. std::map<SrcKeyType, DstKeyType> color_map;
  70. std::for_each(cumltv_srchist.begin(), cumltv_srchist.end(), [&](value_t const& v) {
  71. DstKeyType trnsfrmd_key =
  72. static_cast<DstKeyType>((v.second * (max_key - min_key)) / sum + min_key);
  73. color_map[std::get<0>(v.first)] = trnsfrmd_key;
  74. });
  75. std::for_each(src_hist.begin(), src_hist.end(), [&](value_t const& v) {
  76. dst_hist[color_map[std::get<0>(v.first)]] += v.second;
  77. });
  78. return color_map;
  79. }
  80. /// \overload histogram_equalization
  81. /// \ingroup HE
  82. /// @param src_view INPUT source image view
  83. /// @param dst_view OUTPUT Output image view
  84. /// @param bin_width INPUT Histogram bin width
  85. /// @param mask INPUT Specify is mask is to be used
  86. /// @param src_mask INPUT Mask vector over input image
  87. /// \brief Overload for histogram equalization algorithm, takes in both source & destination
  88. /// image views and histogram equalizes the input image.
  89. ///
  90. template <typename SrcView, typename DstView>
  91. void histogram_equalization(
  92. SrcView const& src_view,
  93. DstView const& dst_view,
  94. std::size_t bin_width = 1,
  95. bool mask = false,
  96. std::vector<std::vector<bool>> src_mask = {})
  97. {
  98. gil_function_requires<ImageViewConcept<SrcView>>();
  99. gil_function_requires<MutableImageViewConcept<DstView>>();
  100. static_assert(
  101. color_spaces_are_compatible<
  102. typename color_space_type<SrcView>::type,
  103. typename color_space_type<DstView>::type>::value,
  104. "Source and destination views must have same color space");
  105. // Defining channel type
  106. using source_channel_t = typename channel_type<SrcView>::type;
  107. using dst_channel_t = typename channel_type<DstView>::type;
  108. using coord_t = typename SrcView::x_coord_t;
  109. std::size_t const channels = num_channels<SrcView>::value;
  110. coord_t const width = src_view.width();
  111. coord_t const height = src_view.height();
  112. std::size_t pixel_max = (std::numeric_limits<dst_channel_t>::max)();
  113. std::size_t pixel_min = (std::numeric_limits<dst_channel_t>::min)();
  114. for (std::size_t i = 0; i < channels; i++)
  115. {
  116. histogram<source_channel_t> h;
  117. fill_histogram(nth_channel_view(src_view, i), h, bin_width, false, false, mask, src_mask);
  118. h.normalize();
  119. auto h2 = cumulative_histogram(h);
  120. for (std::ptrdiff_t src_y = 0; src_y < height; ++src_y)
  121. {
  122. auto src_it = nth_channel_view(src_view, i).row_begin(src_y);
  123. auto dst_it = nth_channel_view(dst_view, i).row_begin(src_y);
  124. for (std::ptrdiff_t src_x = 0; src_x < width; ++src_x)
  125. {
  126. if (mask && !src_mask[src_y][src_x])
  127. dst_it[src_x][0] = channel_convert<dst_channel_t>(src_it[src_x][0]);
  128. else
  129. dst_it[src_x][0] = static_cast<dst_channel_t>(
  130. h2[src_it[src_x][0]] * (pixel_max - pixel_min) + pixel_min);
  131. }
  132. }
  133. }
  134. }
  135. }} //namespace boost::gil
  136. #endif