123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- //
- // Copyright 2020 Debabrata Mandal <[email protected]>
- //
- // Distributed under the Boost Software License, Version 1.0
- // See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt
- //
- #ifndef BOOST_GIL_HISTOGRAM_HPP
- #define BOOST_GIL_HISTOGRAM_HPP
- #include <boost/gil/concepts/concept_check.hpp>
- #include <boost/gil/metafunctions.hpp>
- #include <boost/gil/pixel.hpp>
- #include <boost/mp11.hpp>
- #include <boost/type_traits.hpp>
- #include <boost/functional/hash.hpp>
- #include <array>
- #include <iostream>
- #include <tuple>
- #include <utility>
- #include <vector>
- #include <type_traits>
- #include <map>
- #include <unordered_map>
- namespace boost { namespace gil {
- //////////////////////////////////////////////////////////
- /// Histogram
- //////////////////////////////////////////////////////////
- /// \defgroup Histogram Histogram
- /// \brief Contains description of the boost.gil.histogram class, extensions provided in place
- /// of the default class, algorithms over the histogram class (both extensions and the
- /// default class)
- ///
- namespace detail {
- /// \defgroup Histogram-Helpers Histogram-Helpers
- /// \brief Helper implementations supporting the histogram class.
- /// \ingroup Histogram-Helpers
- ///
- template <std::size_t Index, typename... T>
- inline auto hash_tuple_impl(std::size_t&, std::tuple<T...> const&)
- -> typename std::enable_if<Index == sizeof...(T), void>::type
- {
- // terminating case
- }
- /// \ingroup Histogram-Helpers
- ///
- template <std::size_t Index, typename... T>
- inline auto hash_tuple_impl(std::size_t& seed, std::tuple<T...> const& t)
- -> typename std::enable_if<Index != sizeof...(T), void>::type
- {
- boost::hash_combine(seed, std::get<Index>(t));
- hash_tuple_impl<Index + 1>(seed, t);
- }
- /// \ingroup Histogram-Helpers
- /// \brief Functor provided for the hashing of tuples.
- /// The following approach makes use hash_combine from
- /// boost::container_hash. Although there is a direct hashing
- /// available for tuples, this approach will ease adopting in
- /// future to a std::hash_combine. In case std::hash extends
- /// support to tuples this functor as well as the helper
- /// implementation hash_tuple_impl can be removed.
- ///
- template <typename... T>
- struct hash_tuple
- {
- auto operator()(std::tuple<T...> const& t) const -> std::size_t
- {
- std::size_t seed = 0;
- hash_tuple_impl<0>(seed, t);
- return seed;
- }
- };
- /// \ingroup Histogram-Helpers
- /// \todo With C++14 and using auto we don't need the decltype anymore
- ///
- template <typename Pixel, std::size_t... I>
- auto pixel_to_tuple(Pixel const& p, boost::mp11::index_sequence<I...>)
- -> decltype(std::make_tuple(p[I]...))
- {
- return std::make_tuple(p[I]...);
- }
- /// \ingroup Histogram-Helpers
- /// \todo With C++14 and using auto we don't need the decltype anymore
- ///
- template <typename Tuple, std::size_t... I>
- auto tuple_to_tuple(Tuple const& t, boost::mp11::index_sequence<I...>)
- -> decltype(std::make_tuple(std::get<I>(t)...))
- {
- return std::make_tuple(std::get<I>(t)...);
- }
- /// \ingroup Histogram-Helpers
- ///
- template <typename Tuple, std::size_t... I>
- bool tuple_compare(Tuple const& t1, Tuple const& t2, boost::mp11::index_sequence<I...>)
- {
- std::array<bool, std::tuple_size<Tuple>::value> comp_list;
- comp_list = {std::get<I>(t1) <= std::get<I>(t2)...};
- bool comp = true;
- for (std::size_t i = 0; i < comp_list.size(); i++)
- {
- comp = comp & comp_list[i];
- }
- return comp;
- }
- /// \ingroup Histogram-Helpers
- /// \brief Compares 2 tuples and outputs t1 <= t2
- /// Comparison is not in a lexicographic manner but on every element of the tuple hence
- /// (2, 2) > (1, 3) evaluates to false
- ///
- template <typename Tuple>
- bool tuple_compare(Tuple const& t1, Tuple const& t2)
- {
- std::size_t const tuple_size = std::tuple_size<Tuple>::value;
- auto index_list = boost::mp11::make_index_sequence<tuple_size>{};
- return tuple_compare(t1, t2, index_list);
- }
- /// \ingroup Histogram-Helpers
- /// \brief Provides equivalent of std::numeric_limits for type std::tuple
- /// tuple_limit gets called with only tuples having integral elements
- ///
- template <typename Tuple>
- struct tuple_limit
- {
- static constexpr Tuple min()
- {
- return min_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
- }
- static constexpr Tuple max()
- {
- return max_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
- }
- private:
- template <std::size_t... I>
- static constexpr Tuple min_impl(boost::mp11::index_sequence<I...>)
- {
- return std::make_tuple(
- std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::min()...);
- }
- template <std::size_t... I>
- static constexpr Tuple max_impl(boost::mp11::index_sequence<I...>)
- {
- return std::make_tuple(
- std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::max()...);
- }
- };
- /// \ingroup Histogram-Helpers
- /// \brief Filler is used to fill the histogram class with all values between a specified range
- /// This functor is used when sparsefill is false, since all the keys need to be present
- /// in that case.
- /// Currently on 1D implementation is available, extend by adding specialization for 2D
- /// and higher dimensional cases.
- ///
- template <std::size_t Dimension>
- struct filler
- {
- template <typename Container, typename Tuple>
- void operator()(Container&, Tuple&, Tuple&, std::size_t)
- {
- }
- };
- /// \ingroup Histogram-Helpers
- /// \brief Specialisation for 1D histogram.
- template <>
- struct filler<1>
- {
- template <typename Container, typename Tuple>
- void operator()(Container& hist, Tuple& lower, Tuple& upper, std::size_t bin_width = 1)
- {
- for (auto i = std::get<0>(lower); static_cast<std::size_t>(std::get<0>(upper) - i) >= bin_width; i += bin_width)
- {
- hist(i / bin_width) = 0;
- }
- hist(std::get<0>(upper) / bin_width) = 0;
- }
- };
- } //namespace detail
- ///
- /// \class boost::gil::histogram
- /// \ingroup Histogram
- /// \brief Default histogram class provided by boost::gil.
- ///
- /// The class inherits over the std::unordered_map provided by STL. A complete example/tutorial
- /// of how to use the class resides in the docs.
- /// Simple calling syntax for a 3D dimensional histogram :
- /// \code
- /// histogram<int, int , int> h;
- /// h(1, 1, 1) = 0;
- /// \endcode
- /// This is just a starter to what all can be achieved with it, refer to the docs for the
- /// full demo.
- ///
- template <typename... T>
- class histogram : public std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>
- {
- using base_t = std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>;
- using bin_t = boost::mp11::mp_list<T...>;
- using key_t = typename base_t::key_type;
- using mapped_t = typename base_t::mapped_type;
- using value_t = typename base_t::value_type;
- public:
- histogram() = default;
- /// \brief Returns the number of dimensions(axes) the class supports.
- static constexpr std::size_t dimension()
- {
- return std::tuple_size<key_t>::value;
- }
- /// \brief Returns bin value corresponding to specified tuple
- mapped_t& operator()(T... indices)
- {
- auto key = std::make_tuple(indices...);
- std::size_t const index_dimension = std::tuple_size<std::tuple<T...>>::value;
- std::size_t const histogram_dimension = dimension();
- static_assert(histogram_dimension == index_dimension, "Dimensions do not match.");
- return base_t::operator[](key);
- }
- /// \brief Checks if 2 histograms are equal. Ignores type, and checks if
- /// the keys (after type casting) match.
- template <typename OtherType>
- bool equals(OtherType const& otherhist) const
- {
- bool check = (dimension() == otherhist.dimension());
- using other_value_t = typename OtherType::value_type;
- std::for_each(otherhist.begin(), otherhist.end(), [&](other_value_t const& v) {
- key_t key = key_from_tuple(v.first);
- if (base_t::find(key) != base_t::end())
- {
- check = check & (base_t::at(key) == otherhist.at(v.first));
- }
- else
- {
- check = false;
- }
- });
- return check;
- }
- /// \brief Checks if the histogram class is compatible to be used with
- /// a GIL image type
- static constexpr bool is_pixel_compatible()
- {
- using bin_types = boost::mp11::mp_list<T...>;
- return boost::mp11::mp_all_of<bin_types, std::is_arithmetic>::value;
- }
- /// \brief Checks if the histogram class is compatible to be used with
- /// the specified tuple type
- template <typename Tuple>
- bool is_tuple_compatible(Tuple const&)
- {
- std::size_t const tuple_size = std::tuple_size<Tuple>::value;
- std::size_t const histogram_size = dimension();
- // TODO : Explore consequence of using if-constexpr
- using sequence_type = typename std::conditional
- <
- tuple_size >= histogram_size,
- boost::mp11::make_index_sequence<histogram_size>,
- boost::mp11::make_index_sequence<tuple_size>
- >::type;
- if (is_tuple_size_compatible<Tuple>())
- return is_tuple_type_compatible<Tuple>(sequence_type{});
- else
- return false;
- }
- /// \brief Returns a key compatible to be used as the histogram key
- /// from the input tuple
- template <std::size_t... Dimensions, typename Tuple>
- key_t key_from_tuple(Tuple const& t) const
- {
- using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
- std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
- std::size_t const tuple_size = std::tuple_size<Tuple>::value;
- std::size_t const histogram_dimension = dimension();
- static_assert(
- ((index_list_size != 0 && index_list_size == histogram_dimension) ||
- (tuple_size == histogram_dimension)),
- "Tuple and histogram key of different sizes");
- using new_index_list = typename std::conditional
- <
- index_list_size == 0,
- boost::mp11::mp_list_c<std::size_t, 0>,
- index_list
- >::type;
- std::size_t const min =
- boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
- std::size_t const max =
- boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
- static_assert((0 <= min && max < tuple_size) || index_list_size == 0, "Index out of Range");
- using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
- using seq2 = boost::mp11::index_sequence<Dimensions...>;
- // TODO : Explore consequence of using if-constexpr
- using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
- auto key = detail::tuple_to_tuple(t, sequence_type{});
- static_assert(
- is_tuple_type_compatible<Tuple>(seq1{}),
- "Tuple type and histogram type not compatible.");
- return make_histogram_key(key, seq1{});
- }
- /// \brief Returns a histogram compatible key from the input pixel which
- /// can be directly used
- template <std::size_t... Dimensions, typename Pixel>
- key_t key_from_pixel(Pixel const& p) const
- {
- using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
- std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
- std::size_t const pixel_dimension = num_channels<Pixel>::value;
- std::size_t const histogram_dimension = dimension();
- static_assert(
- ((index_list_size != 0 && index_list_size == histogram_dimension) ||
- (index_list_size == 0 && pixel_dimension == histogram_dimension)) &&
- is_pixel_compatible(),
- "Pixels and histogram key are not compatible.");
- using new_index_list = typename std::conditional
- <
- index_list_size == 0,
- boost::mp11::mp_list_c<std::size_t, 0>,
- index_list
- >::type;
- std::size_t const min =
- boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
- std::size_t const max =
- boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
- static_assert(
- (0 <= min && max < pixel_dimension) || index_list_size == 0, "Index out of Range");
- using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
- using seq2 = boost::mp11::index_sequence<Dimensions...>;
- using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
- auto key = detail::pixel_to_tuple(p, sequence_type{});
- return make_histogram_key(key, seq1{});
- }
- /// \brief Return nearest smaller key to specified histogram key
- key_t nearest_key(key_t const& k) const
- {
- using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
- static_assert(
- boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
- "Keys are not comparable.");
- auto nearest_k = k;
- if (base_t::find(k) != base_t::end())
- {
- return nearest_k;
- }
- else
- {
- bool once = true;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- if (v.first <= k)
- {
- if (once)
- {
- once = !once;
- nearest_k = v.first;
- }
- else if (nearest_k < v.first)
- nearest_k = v.first;
- }
- });
- return nearest_k;
- }
- }
- /// \brief Fills the histogram with the input image view
- template <std::size_t... Dimensions, typename SrcView>
- 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)
- {
- gil_function_requires<ImageViewConcept<SrcView>>();
- using channel_t = typename channel_type<SrcView>::type;
- for (std::ptrdiff_t src_y = 0; src_y < srcview.height(); ++src_y)
- {
- auto src_it = srcview.row_begin(src_y);
- for (std::ptrdiff_t src_x = 0; src_x < srcview.width(); ++src_x)
- {
- if (applymask && !mask[src_y][src_x])
- continue;
- auto scaled_px = src_it[src_x];
- static_for_each(scaled_px, [&](channel_t& ch) {
- ch = ch / bin_width;
- });
- auto key = key_from_pixel<Dimensions...>(scaled_px);
- if (!setlimits ||
- (detail::tuple_compare(lower, key) && detail::tuple_compare(key, upper)))
- base_t::operator[](key)++;
- }
- }
- }
- /// \brief Can return a subset or a mask over the current histogram
- template <std::size_t... Dimensions, typename Tuple>
- histogram sub_histogram(Tuple const& t1, Tuple const& t2)
- {
- using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
- std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
- std::size_t const histogram_dimension = dimension();
- std::size_t const min =
- boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
- std::size_t const max =
- boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
- static_assert(
- (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
- "Index out of Range");
- using seq1 = boost::mp11::make_index_sequence<dimension()>;
- using seq2 = boost::mp11::index_sequence<Dimensions...>;
- static_assert(
- is_tuple_type_compatible<Tuple>(seq1{}),
- "Tuple type and histogram type not compatible.");
- auto low = make_histogram_key(t1, seq1{});
- auto low_key = detail::tuple_to_tuple(low, seq2{});
- auto high = make_histogram_key(t2, seq1{});
- auto high_key = detail::tuple_to_tuple(high, seq2{});
- histogram sub_h;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& k) {
- auto tmp_key = detail::tuple_to_tuple(k.first, seq2{});
- if (low_key <= tmp_key && tmp_key <= high_key)
- sub_h[k.first] += base_t::operator[](k.first);
- });
- return sub_h;
- }
- /// \brief Returns a sub-histogram over specified axes
- template <std::size_t... Dimensions>
- histogram<boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<Dimensions>>...> sub_histogram()
- {
- using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
- std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
- std::size_t const histogram_dimension = dimension();
- std::size_t const min =
- boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
- std::size_t const max =
- boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
- static_assert(
- (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
- "Index out of Range");
- histogram<boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<Dimensions>>...> sub_h;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- auto sub_key =
- detail::tuple_to_tuple(v.first, boost::mp11::index_sequence<Dimensions...>{});
- sub_h[sub_key] += base_t::operator[](v.first);
- });
- return sub_h;
- }
- /// \brief Normalize this histogram class
- void normalize()
- {
- double sum = 0.0;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- sum += v.second;
- });
- // std::cout<<(long int)sum<<"asfe";
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- base_t::operator[](v.first) = v.second / sum;
- });
- }
- /// \brief Return the sum count of all bins
- double sum() const
- {
- double sum = 0.0;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- sum += v.second;
- });
- return sum;
- }
- /// \brief Return the minimum key in histogram
- key_t min_key() const
- {
- key_t min_key = base_t::begin()->first;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- if (v.first < min_key)
- min_key = v.first;
- });
- return min_key;
- }
- /// \brief Return the maximum key in histogram
- key_t max_key() const
- {
- key_t max_key = base_t::begin()->first;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- if (v.first > max_key)
- max_key = v.first;
- });
- return max_key;
- }
- /// \brief Return sorted keys in a vector
- std::vector<key_t> sorted_keys() const
- {
- std::vector<key_t> sorted_keys;
- std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
- sorted_keys.push_back(v.first);
- });
- std::sort(sorted_keys.begin(), sorted_keys.end());
- return sorted_keys;
- }
- private:
- template <typename Tuple, std::size_t... I>
- key_t make_histogram_key(Tuple const& t, boost::mp11::index_sequence<I...>) const
- {
- return std::make_tuple(
- static_cast<typename boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>>(
- std::get<I>(t))...);
- }
- template <typename Tuple, std::size_t... I>
- static constexpr bool is_tuple_type_compatible(boost::mp11::index_sequence<I...>)
- {
- using tp = boost::mp11::mp_list
- <
- typename std::is_convertible
- <
- boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>,
- typename std::tuple_element<I, Tuple>::type
- >::type...
- >;
- return boost::mp11::mp_all_of<tp, boost::mp11::mp_to_bool>::value;
- }
- template <typename Tuple>
- static constexpr bool is_tuple_size_compatible()
- {
- return (std::tuple_size<Tuple>::value == dimension());
- }
- };
- ///
- /// \fn void fill_histogram
- /// \ingroup Histogram Algorithms
- /// \tparam SrcView Input image view
- /// \tparam Container Input histogram container
- /// \brief Overload this function to provide support for boost::gil::histogram or
- /// any other external histogram
- ///
- /// Example :
- /// \code
- /// histogram<int> h;
- /// fill_histogram(view(img), h);
- /// \endcode
- ///
- template <typename SrcView, typename Container>
- void fill_histogram(SrcView const&, Container&);
- ///
- /// \fn void fill_histogram
- /// \ingroup Histogram Algorithms
- /// @param srcview Input Input image view
- /// @param hist Output Histogram to be filled
- /// @param bin_width Input Specify the bin widths for the histogram.
- /// @param accumulate Input Specify whether to accumulate over the values already present in h (default = false)
- /// @param sparsaefill Input Specify whether to have a sparse or continuous histogram (default = true)
- /// @param applymask Input Specify if image mask is to be specified
- /// @param mask Input Mask as a 2D vector. Used only if prev argument specified
- /// @param lower Input Lower limit on the values in histogram (default numeric_limit::min() on axes)
- /// @param upper Input Upper limit on the values in histogram (default numeric_limit::max() on axes)
- /// @param setlimits Input Use specified limits if this is true (default is false)
- /// \brief Overload version of fill_histogram
- ///
- /// Takes a third argument to determine whether to clear container before filling.
- /// For eg, when there is a need to accumulate the histograms do
- /// \code
- /// fill_histogram(view(img), hist, true);
- /// \endcode
- ///
- template <std::size_t... Dimensions, typename SrcView, typename... T>
- void fill_histogram(
- SrcView const& srcview,
- histogram<T...>& hist,
- std::size_t bin_width = 1,
- bool accumulate = false,
- bool sparsefill = true,
- bool applymask = false,
- std::vector<std::vector<bool>> mask = {},
- typename histogram<T...>::key_type lower =
- detail::tuple_limit<typename histogram<T...>::key_type>::min(),
- typename histogram<T...>::key_type upper =
- detail::tuple_limit<typename histogram<T...>::key_type>::max(),
- bool setlimits = false)
- {
- if (!accumulate)
- hist.clear();
- detail::filler<histogram<T...>::dimension()> f;
- if (!sparsefill)
- f(hist, lower, upper, bin_width);
- hist.template fill<Dimensions...>(srcview, bin_width, applymask, mask, lower, upper, setlimits);
- }
- ///
- /// \fn void cumulative_histogram(Container&)
- /// \ingroup Histogram Algorithms
- /// \tparam Container Input histogram container
- /// \brief Optionally overload this function with any external histogram class
- ///
- /// Cumulative histogram is calculated over any arbitrary dimensional
- /// histogram. The only tradeoff could be the runtime complexity which in
- /// the worst case would be max( #pixel_values , #bins ) * #dimensions.
- /// For single dimensional histograms the complexity has been brought down to
- /// #bins * log( #bins ) by sorting the keys and then calculating the cumulative version.
- ///
- template <typename Container>
- auto cumulative_histogram(Container const&) -> Container;
- template <typename... T>
- auto cumulative_histogram(histogram<T...> const& hist) -> histogram<T...>
- {
- using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
- static_assert(
- boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
- "Cumulative histogram not possible of this type");
- using histogram_t = histogram<T...>;
- using pair_t = std::pair<typename histogram_t::key_type, typename histogram_t::mapped_type>;
- using value_t = typename histogram_t::value_type;
- histogram_t cumulative_hist;
- std::size_t const dims = histogram_t::dimension();
- if (dims == 1)
- {
- std::vector<pair_t> sorted_keys(hist.size());
- std::size_t counter = 0;
- std::for_each(hist.begin(), hist.end(), [&](value_t const& v) {
- sorted_keys[counter++] = std::make_pair(v.first, v.second);
- });
- std::sort(sorted_keys.begin(), sorted_keys.end());
- auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
- for (std::size_t i = 0; i < sorted_keys.size(); ++i)
- {
- cumulative_counter += sorted_keys[i].second;
- cumulative_hist[(sorted_keys[i].first)] = cumulative_counter;
- }
- }
- else
- {
- std::for_each(hist.begin(), hist.end(), [&](value_t const& v1) {
- auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
- std::for_each(hist.begin(), hist.end(), [&](value_t const& v2) {
- bool comp = detail::tuple_compare(
- v2.first, v1.first,
- boost::mp11::make_index_sequence<histogram_t::dimension()>{});
- if (comp)
- cumulative_counter += hist.at(v2.first);
- });
- cumulative_hist[v1.first] = cumulative_counter;
- });
- }
- return cumulative_hist;
- }
- }} //namespace boost::gil
- #endif
|