9 #ifndef BOOST_GIL_IMAGE_PROCESSING_HISTOGRAM_MATCHING_HPP
10 #define BOOST_GIL_IMAGE_PROCESSING_HISTOGRAM_MATCHING_HPP
12 #include <boost/gil/algorithm.hpp>
13 #include <boost/gil/histogram.hpp>
14 #include <boost/gil/image.hpp>
21 namespace boost {
namespace gil {
45 template <
typename SrcKeyType,
typename RefKeyType>
46 std::map<SrcKeyType, SrcKeyType>
47 histogram_matching(histogram<SrcKeyType>
const& src_hist, histogram<RefKeyType>
const& ref_hist)
49 histogram<SrcKeyType> dst_hist;
50 return histogram_matching(src_hist, ref_hist, dst_hist);
65 template <
typename SrcKeyType,
typename RefKeyType,
typename DstKeyType>
66 std::map<SrcKeyType, DstKeyType> histogram_matching(
67 histogram<SrcKeyType>
const& src_hist,
68 histogram<RefKeyType>
const& ref_hist,
69 histogram<DstKeyType>& dst_hist)
72 std::is_integral<SrcKeyType>::value &&
73 std::is_integral<RefKeyType>::value &&
74 std::is_integral<DstKeyType>::value,
75 "Source, Refernce or Destination histogram type is not appropriate.");
77 using value_t =
typename histogram<SrcKeyType>::value_type;
79 double src_sum = src_hist.sum();
80 double ref_sum = ref_hist.sum();
81 auto cumltv_srchist = cumulative_histogram(src_hist);
82 auto cumltv_refhist = cumulative_histogram(ref_hist);
83 std::map<SrcKeyType, RefKeyType> inverse_mapping;
85 std::vector<typename histogram<RefKeyType>::key_type> src_keys, ref_keys;
86 src_keys = src_hist.sorted_keys();
87 ref_keys = ref_hist.sorted_keys();
88 std::ptrdiff_t start = ref_keys.size() - 1;
91 ref_max = std::get<0>(ref_keys[start]);
93 for (std::ptrdiff_t j = src_keys.size() - 1; j >= 0; --j)
95 double src_val = (cumltv_srchist[src_keys[j]] * ref_sum) / src_sum;
96 while (cumltv_refhist[ref_keys[start]] > src_val && start > 0)
100 if (std::abs(cumltv_refhist[ref_keys[start]] - src_val) >
101 std::abs(cumltv_refhist(std::min<RefKeyType>(ref_max, std::get<0>(ref_keys[start + 1]))) -
104 inverse_mapping[std::get<0>(src_keys[j])] =
105 std::min<RefKeyType>(ref_max, std::get<0>(ref_keys[start + 1]));
109 inverse_mapping[std::get<0>(src_keys[j])] = std::get<0>(ref_keys[start]);
114 std::for_each(src_hist.begin(), src_hist.end(), [&](value_t
const& v) {
115 dst_hist[inverse_mapping[std::get<0>(v.first)]] += v.second;
117 return inverse_mapping;
133 template <
typename SrcView,
typename ReferenceView,
typename DstView>
134 void histogram_matching(
135 SrcView
const& src_view,
136 ReferenceView
const& ref_view,
137 DstView
const& dst_view,
138 std::size_t bin_width = 1,
140 std::vector<std::vector<bool>> src_mask = {},
141 std::vector<std::vector<bool>> ref_mask = {})
143 gil_function_requires<ImageViewConcept<SrcView>>();
144 gil_function_requires<ImageViewConcept<ReferenceView>>();
145 gil_function_requires<MutableImageViewConcept<DstView>>();
148 color_spaces_are_compatible<
149 typename color_space_type<SrcView>::type,
150 typename color_space_type<ReferenceView>::type>::value,
151 "Source and reference view must have same color space");
154 color_spaces_are_compatible<
155 typename color_space_type<SrcView>::type,
156 typename color_space_type<DstView>::type>::value,
157 "Source and destination view must have same color space");
160 using source_channel_t =
typename channel_type<SrcView>::type;
161 using ref_channel_t =
typename channel_type<ReferenceView>::type;
162 using dst_channel_t =
typename channel_type<DstView>::type;
163 using coord_t =
typename SrcView::x_coord_t;
165 std::size_t
const channels = num_channels<SrcView>::value;
166 coord_t
const width = src_view.width();
167 coord_t
const height = src_view.height();
168 source_channel_t src_pixel_min = std::numeric_limits<source_channel_t>::min();
169 source_channel_t src_pixel_max = std::numeric_limits<source_channel_t>::max();
170 ref_channel_t ref_pixel_min = std::numeric_limits<ref_channel_t>::min();
171 ref_channel_t ref_pixel_max = std::numeric_limits<ref_channel_t>::max();
173 for (std::size_t i = 0; i < channels; i++)
175 histogram<source_channel_t> src_histogram;
176 histogram<ref_channel_t> ref_histogram;
178 nth_channel_view(src_view, i), src_histogram, bin_width,
false,
false, mask, src_mask,
179 std::tuple<source_channel_t>(src_pixel_min),
180 std::tuple<source_channel_t>(src_pixel_max),
true);
182 nth_channel_view(ref_view, i), ref_histogram, bin_width,
false,
false, mask, ref_mask,
183 std::tuple<ref_channel_t>(ref_pixel_min), std::tuple<ref_channel_t>(ref_pixel_max),
185 auto inverse_mapping = histogram_matching(src_histogram, ref_histogram);
186 for (std::ptrdiff_t src_y = 0; src_y < height; ++src_y)
190 for (std::ptrdiff_t src_x = 0; src_x < width; ++src_x)
192 if (mask && !src_mask[src_y][src_x])
193 dst_it[src_x][0] = src_it[src_x][0];
196 static_cast<dst_channel_t
>(inverse_mapping[src_it[src_x][0]]);