9 #ifndef BOOST_GIL_HISTOGRAM_HPP
10 #define BOOST_GIL_HISTOGRAM_HPP
12 #include <boost/gil/concepts/concept_check.hpp>
13 #include <boost/gil/metafunctions.hpp>
14 #include <boost/gil/pixel.hpp>
16 #include <boost/mp11.hpp>
17 #include <boost/type_traits.hpp>
18 #include <boost/functional/hash.hpp>
25 #include <type_traits>
27 #include <unordered_map>
29 namespace boost {
namespace gil {
47 template <std::size_t Index,
typename... T>
48 inline auto hash_tuple_impl(std::size_t&, std::tuple<T...>
const&)
49 ->
typename std::enable_if<Index ==
sizeof...(T),
void>::type
56 template <std::size_t Index,
typename... T>
57 inline auto hash_tuple_impl(std::size_t& seed, std::tuple<T...>
const& t)
58 ->
typename std::enable_if<Index !=
sizeof...(T),
void>::type
60 boost::hash_combine(seed, std::get<Index>(t));
61 hash_tuple_impl<Index + 1>(seed, t);
73 template <
typename... T>
76 auto operator()(std::tuple<T...>
const& t)
const -> std::size_t
79 hash_tuple_impl<0>(seed, t);
87 template <
typename Pixel, std::size_t... I>
89 -> decltype(std::make_tuple(p[I]...))
91 return std::make_tuple(p[I]...);
97 template <
typename Tuple, std::size_t... I>
99 -> decltype(std::make_tuple(std::get<I>(t)...))
101 return std::make_tuple(std::get<I>(t)...);
106 template <
typename Tuple, std::size_t... I>
107 bool tuple_compare(Tuple
const& t1, Tuple
const& t2, boost::mp11::index_sequence<I...>)
109 std::array<bool, std::tuple_size<Tuple>::value> comp_list;
110 comp_list = {std::get<I>(t1) <= std::get<I>(t2)...};
112 for (std::size_t i = 0; i < comp_list.size(); i++)
114 comp = comp & comp_list[i];
124 template <
typename Tuple>
127 std::size_t
const tuple_size = std::tuple_size<Tuple>::value;
128 auto index_list = boost::mp11::make_index_sequence<tuple_size>{};
136 template <
typename Tuple>
139 static constexpr Tuple (min)()
141 return min_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
143 static constexpr Tuple (max)()
145 return max_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
149 template <std::size_t... I>
150 static constexpr Tuple min_impl(boost::mp11::index_sequence<I...>)
152 return std::make_tuple(
153 (std::numeric_limits<
typename std::tuple_element<I, Tuple>::type>::min)()...);
156 template <std::size_t... I>
157 static constexpr Tuple max_impl(boost::mp11::index_sequence<I...>)
159 return std::make_tuple(
160 (std::numeric_limits<
typename std::tuple_element<I, Tuple>::type>::max)()...);
171 template <std::
size_t Dimension>
174 template <
typename Container,
typename Tuple>
175 void operator()(Container&, Tuple&, Tuple&, std::size_t)
185 template <
typename Container,
typename Tuple>
186 void operator()(Container& hist, Tuple& lower, Tuple& upper, std::size_t bin_width = 1)
188 for (
auto i = std::get<0>(lower);
static_cast<std::size_t
>(std::get<0>(upper) - i) >= bin_width; i += bin_width)
190 hist(i / bin_width) = 0;
192 hist(std::get<0>(upper) / bin_width) = 0;
213 template <
typename... T>
214 class histogram :
public std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>
216 using base_t = std::unordered_map<std::tuple<T...>, double,
detail::hash_tuple<T...>>;
217 using bin_t = boost::mp11::mp_list<T...>;
218 using key_t =
typename base_t::key_type;
219 using mapped_t =
typename base_t::mapped_type;
220 using value_t =
typename base_t::value_type;
228 return std::tuple_size<key_t>::value;
234 auto key = std::make_tuple(indices...);
235 std::size_t
const index_dimension = std::tuple_size<std::tuple<T...>>::value;
236 std::size_t
const histogram_dimension =
dimension();
237 static_assert(histogram_dimension == index_dimension,
"Dimensions do not match.");
239 return base_t::operator[](key);
244 template <
typename OtherType>
245 bool equals(OtherType
const& otherhist)
const
247 bool check = (
dimension() == otherhist.dimension());
249 using other_value_t =
typename OtherType::value_type;
250 std::for_each(otherhist.begin(), otherhist.end(), [&](other_value_t
const& v) {
251 key_t key = key_from_tuple(v.first);
252 if (base_t::find(key) != base_t::end())
254 check = check & (base_t::at(key) == otherhist.at(v.first));
268 using bin_types = boost::mp11::mp_list<T...>;
269 return boost::mp11::mp_all_of<bin_types, std::is_arithmetic>::value;
274 template <
typename Tuple>
277 std::size_t
const tuple_size = std::tuple_size<Tuple>::value;
278 std::size_t
const histogram_size = dimension();
280 using sequence_type =
typename std::conditional
282 tuple_size >= histogram_size,
283 boost::mp11::make_index_sequence<histogram_size>,
284 boost::mp11::make_index_sequence<tuple_size>
287 if (is_tuple_size_compatible<Tuple>())
288 return is_tuple_type_compatible<Tuple>(sequence_type{});
295 template <std::size_t... Dimensions,
typename Tuple>
298 using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
299 std::size_t
const index_list_size = boost::mp11::mp_size<index_list>::value;
300 std::size_t
const tuple_size = std::tuple_size<Tuple>::value;
301 std::size_t
const histogram_dimension = dimension();
304 ((index_list_size != 0 && index_list_size == histogram_dimension) ||
305 (tuple_size == histogram_dimension)),
306 "Tuple and histogram key of different sizes");
308 using new_index_list =
typename std::conditional
310 index_list_size == 0,
311 boost::mp11::mp_list_c<std::size_t, 0>,
315 std::size_t
const min =
316 boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
318 std::size_t
const max =
319 boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
321 static_assert((0 <= min && max < tuple_size) || index_list_size == 0,
"Index out of Range");
323 using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
324 using seq2 = boost::mp11::index_sequence<Dimensions...>;
326 using sequence_type =
typename std::conditional<index_list_size == 0, seq1, seq2>::type;
330 is_tuple_type_compatible<Tuple>(seq1{}),
331 "Tuple type and histogram type not compatible.");
333 return make_histogram_key(key, seq1{});
338 template <std::size_t... Dimensions,
typename Pixel>
341 using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
342 std::size_t
const index_list_size = boost::mp11::mp_size<index_list>::value;
344 std::size_t
const histogram_dimension = dimension();
347 ((index_list_size != 0 && index_list_size == histogram_dimension) ||
348 (index_list_size == 0 && pixel_dimension == histogram_dimension)) &&
349 is_pixel_compatible(),
350 "Pixels and histogram key are not compatible.");
352 using new_index_list =
typename std::conditional
354 index_list_size == 0,
355 boost::mp11::mp_list_c<std::size_t, 0>,
359 std::size_t
const min =
360 boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
362 std::size_t
const max =
363 boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
366 (0 <= min && max < pixel_dimension) || index_list_size == 0,
"Index out of Range");
368 using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
369 using seq2 = boost::mp11::index_sequence<Dimensions...>;
370 using sequence_type =
typename std::conditional<index_list_size == 0, seq1, seq2>::type;
373 return make_histogram_key(key, seq1{});
379 using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
381 boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
382 "Keys are not comparable.");
384 if (base_t::find(k) != base_t::end())
391 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
399 else if (nearest_k < v.first)
408 template <std::size_t... Dimensions,
typename SrcView>
410 SrcView
const& srcview,
411 std::size_t bin_width = 1,
412 bool applymask =
false,
413 std::vector<std::vector<bool>> mask = {},
414 key_t lower = key_t(),
415 key_t upper = key_t(),
416 bool setlimits =
false)
418 gil_function_requires<ImageViewConcept<SrcView>>();
421 for (std::ptrdiff_t src_y = 0; src_y < srcview.height(); ++src_y)
423 auto src_it = srcview.row_begin(src_y);
424 for (std::ptrdiff_t src_x = 0; src_x < srcview.width(); ++src_x)
426 if (applymask && !mask[src_y][src_x])
428 auto scaled_px = src_it[src_x];
429 static_for_each(scaled_px, [&](channel_t& ch) {
432 auto key = key_from_pixel<Dimensions...>(scaled_px);
435 base_t::operator[](key)++;
441 template <std::size_t... Dimensions,
typename Tuple>
444 using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
445 std::size_t
const index_list_size = boost::mp11::mp_size<index_list>::value;
446 std::size_t
const histogram_dimension = dimension();
448 std::size_t
const min =
449 boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
451 std::size_t
const max =
452 boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
455 (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
456 "Index out of Range");
458 using seq1 = boost::mp11::make_index_sequence<dimension()>;
459 using seq2 = boost::mp11::index_sequence<Dimensions...>;
462 is_tuple_type_compatible<Tuple>(seq1{}),
463 "Tuple type and histogram type not compatible.");
465 auto low = make_histogram_key(t1, seq1{});
467 auto high = make_histogram_key(t2, seq1{});
471 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& k) {
473 if (low_key <= tmp_key && tmp_key <= high_key)
474 sub_h[k.first] += base_t::operator[](k.first);
480 template <std::size_t... Dimensions>
483 using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
484 std::size_t
const index_list_size = boost::mp11::mp_size<index_list>::value;
485 std::size_t
const histogram_dimension = dimension();
487 std::size_t
const min =
488 boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
490 std::size_t
const max =
491 boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
494 (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
495 "Index out of Range");
499 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
502 sub_h[sub_key] += base_t::operator[](v.first);
511 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
515 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
516 base_t::operator[](v.first) = v.second / sum;
524 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
533 key_t min_key = base_t::begin()->first;
534 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
535 if (v.first < min_key)
544 key_t max_key = base_t::begin()->first;
545 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
546 if (v.first > max_key)
555 std::vector<key_t> sorted_keys;
556 std::for_each(base_t::begin(), base_t::end(), [&](value_t
const& v) {
557 sorted_keys.push_back(v.first);
559 std::sort(sorted_keys.begin(), sorted_keys.end());
564 template <
typename Tuple, std::size_t... I>
565 key_t make_histogram_key(Tuple
const& t, boost::mp11::index_sequence<I...>)
const
567 return std::make_tuple(
568 static_cast<typename boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>
>>(
572 template <
typename Tuple, std::size_t... I>
573 static constexpr
bool is_tuple_type_compatible(boost::mp11::index_sequence<I...>)
575 using tp = boost::mp11::mp_list
577 typename std::is_convertible
579 boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>,
580 typename std::tuple_element<I, Tuple>::type
583 return boost::mp11::mp_all_of<tp, boost::mp11::mp_to_bool>::value;
586 template <
typename Tuple>
587 static constexpr
bool is_tuple_size_compatible()
589 return (std::tuple_size<Tuple>::value == dimension());
607 template <
typename SrcView,
typename Container>
608 void fill_histogram(SrcView
const&, Container&);
631 template <std::size_t... Dimensions,
typename SrcView,
typename... T>
633 SrcView
const& srcview,
634 histogram<T...>& hist,
635 std::size_t bin_width = 1,
636 bool accumulate =
false,
637 bool sparsefill =
true,
638 bool applymask =
false,
639 std::vector<std::vector<bool>> mask = {},
640 typename histogram<T...>::key_type lower =
641 (detail::tuple_limit<
typename histogram<T...>::key_type>::min)(),
642 typename histogram<T...>::key_type upper =
643 (detail::tuple_limit<
typename histogram<T...>::key_type>::max)(),
644 bool setlimits =
false)
649 detail::filler<histogram<T...>::dimension()> f;
651 f(hist, lower, upper, bin_width);
653 hist.template
fill<Dimensions...>(srcview, bin_width, applymask, mask, lower, upper, setlimits);
668 template <
typename Container>
669 auto cumulative_histogram(Container
const&) -> Container;
671 template <
typename... T>
672 auto cumulative_histogram(histogram<T...>
const& hist) -> histogram<T...>
674 using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
676 boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
677 "Cumulative histogram not possible of this type");
679 using histogram_t = histogram<T...>;
680 using pair_t = std::pair<typename histogram_t::key_type, typename histogram_t::mapped_type>;
681 using value_t =
typename histogram_t::value_type;
683 histogram_t cumulative_hist;
684 std::size_t
const dims = histogram_t::dimension();
687 std::vector<pair_t> sorted_keys(hist.size());
688 std::size_t counter = 0;
689 std::for_each(hist.begin(), hist.end(), [&](value_t
const& v) {
690 sorted_keys[counter++] = std::make_pair(v.first, v.second);
692 std::sort(sorted_keys.begin(), sorted_keys.end());
693 auto cumulative_counter =
static_cast<typename histogram_t::mapped_type
>(0);
694 for (std::size_t i = 0; i < sorted_keys.size(); ++i)
696 cumulative_counter += sorted_keys[i].second;
697 cumulative_hist[(sorted_keys[i].first)] = cumulative_counter;
702 std::for_each(hist.begin(), hist.end(), [&](value_t
const& v1) {
703 auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
704 std::for_each(hist.begin(), hist.end(), [&](value_t const& v2) {
705 bool comp = detail::tuple_compare(
707 boost::mp11::make_index_sequence<histogram_t::dimension()>{});
709 cumulative_counter += hist.at(v2.first);
711 cumulative_hist[v1.first] = cumulative_counter;
714 return cumulative_hist;
Default histogram class provided by boost::gil.
Definition: histogram.hpp:215
static constexpr bool is_pixel_compatible()
Checks if the histogram class is compatible to be used with a GIL image type.
Definition: histogram.hpp:266
key_t key_from_tuple(Tuple const &t) const
Returns a key compatible to be used as the histogram key from the input tuple.
Definition: histogram.hpp:296
histogram< boost::mp11::mp_at< bin_t, boost::mp11::mp_size_t< Dimensions > >... > sub_histogram()
Returns a sub-histogram over specified axes.
Definition: histogram.hpp:481
mapped_t & operator()(T... indices)
Returns bin value corresponding to specified tuple.
Definition: histogram.hpp:232
static constexpr std::size_t dimension()
Returns the number of dimensions(axes) the class supports.
Definition: histogram.hpp:226
histogram sub_histogram(Tuple const &t1, Tuple const &t2)
Can return a subset or a mask over the current histogram.
Definition: histogram.hpp:442
key_t min_key() const
Return the minimum key in histogram.
Definition: histogram.hpp:531
key_t key_from_pixel(Pixel const &p) const
Returns a histogram compatible key from the input pixel which can be directly used.
Definition: histogram.hpp:339
std::vector< key_t > sorted_keys() const
Return sorted keys in a vector.
Definition: histogram.hpp:553
key_t nearest_key(key_t const &k) const
Return nearest smaller key to specified histogram key.
Definition: histogram.hpp:377
void normalize()
Normalize this histogram class.
Definition: histogram.hpp:508
void fill(SrcView const &srcview, std::size_t bin_width=1, bool applymask=false, std::vector< std::vector< bool >> mask={}, key_t lower=key_t(), key_t upper=key_t(), bool setlimits=false)
Fills the histogram with the input image view.
Definition: histogram.hpp:409
bool is_tuple_compatible(Tuple const &)
Checks if the histogram class is compatible to be used with the specified tuple type.
Definition: histogram.hpp:275
double sum() const
Return the sum count of all bins.
Definition: histogram.hpp:521
key_t max_key() const
Return the maximum key in histogram.
Definition: histogram.hpp:542
bool equals(OtherType const &otherhist) const
Checks if 2 histograms are equal. Ignores type, and checks if the keys (after type casting) match.
Definition: histogram.hpp:245
auto tuple_to_tuple(Tuple const &t, boost::mp11::index_sequence< I... >) -> decltype(std::make_tuple(std::get< I >(t)...))
Definition: histogram.hpp:98
auto pixel_to_tuple(Pixel const &p, boost::mp11::index_sequence< I... >) -> decltype(std::make_tuple(p[I]...))
Definition: histogram.hpp:88
bool tuple_compare(Tuple const &t1, Tuple const &t2)
Compares 2 tuples and outputs t1 <= t2 Comparison is not in a lexicographic manner but on every eleme...
Definition: histogram.hpp:125
void fill(boost::gil::iterator_from_2d< IL > first, boost::gil::iterator_from_2d< IL > last, const V &val)
std::fill(I,I,V) with I being a iterator_from_2d
Definition: algorithm.hpp:369
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
Definition: color_convert.hpp:31
Filler is used to fill the histogram class with all values between a specified range This functor is ...
Definition: histogram.hpp:173
Functor provided for the hashing of tuples. The following approach makes use hash_combine from boost:...
Definition: histogram.hpp:75
Provides equivalent of std::numeric_limits for type std::tuple tuple_limit gets called with only tupl...
Definition: histogram.hpp:138
Returns the number of channels of a pixel-based GIL construct.
Definition: pixel.hpp:54