histogram.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. //
  2. // Copyright 2020 Debabrata Mandal <[email protected]>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_HISTOGRAM_HPP
  9. #define BOOST_GIL_HISTOGRAM_HPP
  10. #include <boost/gil/concepts/concept_check.hpp>
  11. #include <boost/gil/metafunctions.hpp>
  12. #include <boost/gil/pixel.hpp>
  13. #include <boost/mp11.hpp>
  14. #include <boost/type_traits.hpp>
  15. #include <boost/functional/hash.hpp>
  16. #include <array>
  17. #include <iostream>
  18. #include <tuple>
  19. #include <utility>
  20. #include <vector>
  21. #include <type_traits>
  22. #include <map>
  23. #include <unordered_map>
  24. namespace boost { namespace gil {
  25. //////////////////////////////////////////////////////////
  26. /// Histogram
  27. //////////////////////////////////////////////////////////
  28. /// \defgroup Histogram Histogram
  29. /// \brief Contains description of the boost.gil.histogram class, extensions provided in place
  30. /// of the default class, algorithms over the histogram class (both extensions and the
  31. /// default class)
  32. ///
  33. namespace detail {
  34. /// \defgroup Histogram-Helpers Histogram-Helpers
  35. /// \brief Helper implementations supporting the histogram class.
  36. /// \ingroup Histogram-Helpers
  37. ///
  38. template <std::size_t Index, typename... T>
  39. inline auto hash_tuple_impl(std::size_t&, std::tuple<T...> const&)
  40. -> typename std::enable_if<Index == sizeof...(T), void>::type
  41. {
  42. // terminating case
  43. }
  44. /// \ingroup Histogram-Helpers
  45. ///
  46. template <std::size_t Index, typename... T>
  47. inline auto hash_tuple_impl(std::size_t& seed, std::tuple<T...> const& t)
  48. -> typename std::enable_if<Index != sizeof...(T), void>::type
  49. {
  50. boost::hash_combine(seed, std::get<Index>(t));
  51. hash_tuple_impl<Index + 1>(seed, t);
  52. }
  53. /// \ingroup Histogram-Helpers
  54. /// \brief Functor provided for the hashing of tuples.
  55. /// The following approach makes use hash_combine from
  56. /// boost::container_hash. Although there is a direct hashing
  57. /// available for tuples, this approach will ease adopting in
  58. /// future to a std::hash_combine. In case std::hash extends
  59. /// support to tuples this functor as well as the helper
  60. /// implementation hash_tuple_impl can be removed.
  61. ///
  62. template <typename... T>
  63. struct hash_tuple
  64. {
  65. auto operator()(std::tuple<T...> const& t) const -> std::size_t
  66. {
  67. std::size_t seed = 0;
  68. hash_tuple_impl<0>(seed, t);
  69. return seed;
  70. }
  71. };
  72. /// \ingroup Histogram-Helpers
  73. /// \todo With C++14 and using auto we don't need the decltype anymore
  74. ///
  75. template <typename Pixel, std::size_t... I>
  76. auto pixel_to_tuple(Pixel const& p, boost::mp11::index_sequence<I...>)
  77. -> decltype(std::make_tuple(p[I]...))
  78. {
  79. return std::make_tuple(p[I]...);
  80. }
  81. /// \ingroup Histogram-Helpers
  82. /// \todo With C++14 and using auto we don't need the decltype anymore
  83. ///
  84. template <typename Tuple, std::size_t... I>
  85. auto tuple_to_tuple(Tuple const& t, boost::mp11::index_sequence<I...>)
  86. -> decltype(std::make_tuple(std::get<I>(t)...))
  87. {
  88. return std::make_tuple(std::get<I>(t)...);
  89. }
  90. /// \ingroup Histogram-Helpers
  91. ///
  92. template <typename Tuple, std::size_t... I>
  93. bool tuple_compare(Tuple const& t1, Tuple const& t2, boost::mp11::index_sequence<I...>)
  94. {
  95. std::array<bool, std::tuple_size<Tuple>::value> comp_list;
  96. comp_list = {std::get<I>(t1) <= std::get<I>(t2)...};
  97. bool comp = true;
  98. for (std::size_t i = 0; i < comp_list.size(); i++)
  99. {
  100. comp = comp & comp_list[i];
  101. }
  102. return comp;
  103. }
  104. /// \ingroup Histogram-Helpers
  105. /// \brief Compares 2 tuples and outputs t1 <= t2
  106. /// Comparison is not in a lexicographic manner but on every element of the tuple hence
  107. /// (2, 2) > (1, 3) evaluates to false
  108. ///
  109. template <typename Tuple>
  110. bool tuple_compare(Tuple const& t1, Tuple const& t2)
  111. {
  112. std::size_t const tuple_size = std::tuple_size<Tuple>::value;
  113. auto index_list = boost::mp11::make_index_sequence<tuple_size>{};
  114. return tuple_compare(t1, t2, index_list);
  115. }
  116. /// \ingroup Histogram-Helpers
  117. /// \brief Provides equivalent of std::numeric_limits for type std::tuple
  118. /// tuple_limit gets called with only tuples having integral elements
  119. ///
  120. template <typename Tuple>
  121. struct tuple_limit
  122. {
  123. static constexpr Tuple min()
  124. {
  125. return min_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
  126. }
  127. static constexpr Tuple max()
  128. {
  129. return max_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
  130. }
  131. private:
  132. template <std::size_t... I>
  133. static constexpr Tuple min_impl(boost::mp11::index_sequence<I...>)
  134. {
  135. return std::make_tuple(
  136. std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::min()...);
  137. }
  138. template <std::size_t... I>
  139. static constexpr Tuple max_impl(boost::mp11::index_sequence<I...>)
  140. {
  141. return std::make_tuple(
  142. std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::max()...);
  143. }
  144. };
  145. /// \ingroup Histogram-Helpers
  146. /// \brief Filler is used to fill the histogram class with all values between a specified range
  147. /// This functor is used when sparsefill is false, since all the keys need to be present
  148. /// in that case.
  149. /// Currently on 1D implementation is available, extend by adding specialization for 2D
  150. /// and higher dimensional cases.
  151. ///
  152. template <std::size_t Dimension>
  153. struct filler
  154. {
  155. template <typename Container, typename Tuple>
  156. void operator()(Container&, Tuple&, Tuple&, std::size_t)
  157. {
  158. }
  159. };
  160. /// \ingroup Histogram-Helpers
  161. /// \brief Specialisation for 1D histogram.
  162. template <>
  163. struct filler<1>
  164. {
  165. template <typename Container, typename Tuple>
  166. void operator()(Container& hist, Tuple& lower, Tuple& upper, std::size_t bin_width = 1)
  167. {
  168. for (auto i = std::get<0>(lower); static_cast<std::size_t>(std::get<0>(upper) - i) >= bin_width; i += bin_width)
  169. {
  170. hist(i / bin_width) = 0;
  171. }
  172. hist(std::get<0>(upper) / bin_width) = 0;
  173. }
  174. };
  175. } //namespace detail
  176. ///
  177. /// \class boost::gil::histogram
  178. /// \ingroup Histogram
  179. /// \brief Default histogram class provided by boost::gil.
  180. ///
  181. /// The class inherits over the std::unordered_map provided by STL. A complete example/tutorial
  182. /// of how to use the class resides in the docs.
  183. /// Simple calling syntax for a 3D dimensional histogram :
  184. /// \code
  185. /// histogram<int, int , int> h;
  186. /// h(1, 1, 1) = 0;
  187. /// \endcode
  188. /// This is just a starter to what all can be achieved with it, refer to the docs for the
  189. /// full demo.
  190. ///
  191. template <typename... T>
  192. class histogram : public std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>
  193. {
  194. using base_t = std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>;
  195. using bin_t = boost::mp11::mp_list<T...>;
  196. using key_t = typename base_t::key_type;
  197. using mapped_t = typename base_t::mapped_type;
  198. using value_t = typename base_t::value_type;
  199. public:
  200. histogram() = default;
  201. /// \brief Returns the number of dimensions(axes) the class supports.
  202. static constexpr std::size_t dimension()
  203. {
  204. return std::tuple_size<key_t>::value;
  205. }
  206. /// \brief Returns bin value corresponding to specified tuple
  207. mapped_t& operator()(T... indices)
  208. {
  209. auto key = std::make_tuple(indices...);
  210. std::size_t const index_dimension = std::tuple_size<std::tuple<T...>>::value;
  211. std::size_t const histogram_dimension = dimension();
  212. static_assert(histogram_dimension == index_dimension, "Dimensions do not match.");
  213. return base_t::operator[](key);
  214. }
  215. /// \brief Checks if 2 histograms are equal. Ignores type, and checks if
  216. /// the keys (after type casting) match.
  217. template <typename OtherType>
  218. bool equals(OtherType const& otherhist) const
  219. {
  220. bool check = (dimension() == otherhist.dimension());
  221. using other_value_t = typename OtherType::value_type;
  222. std::for_each(otherhist.begin(), otherhist.end(), [&](other_value_t const& v) {
  223. key_t key = key_from_tuple(v.first);
  224. if (base_t::find(key) != base_t::end())
  225. {
  226. check = check & (base_t::at(key) == otherhist.at(v.first));
  227. }
  228. else
  229. {
  230. check = false;
  231. }
  232. });
  233. return check;
  234. }
  235. /// \brief Checks if the histogram class is compatible to be used with
  236. /// a GIL image type
  237. static constexpr bool is_pixel_compatible()
  238. {
  239. using bin_types = boost::mp11::mp_list<T...>;
  240. return boost::mp11::mp_all_of<bin_types, std::is_arithmetic>::value;
  241. }
  242. /// \brief Checks if the histogram class is compatible to be used with
  243. /// the specified tuple type
  244. template <typename Tuple>
  245. bool is_tuple_compatible(Tuple const&)
  246. {
  247. std::size_t const tuple_size = std::tuple_size<Tuple>::value;
  248. std::size_t const histogram_size = dimension();
  249. // TODO : Explore consequence of using if-constexpr
  250. using sequence_type = typename std::conditional
  251. <
  252. tuple_size >= histogram_size,
  253. boost::mp11::make_index_sequence<histogram_size>,
  254. boost::mp11::make_index_sequence<tuple_size>
  255. >::type;
  256. if (is_tuple_size_compatible<Tuple>())
  257. return is_tuple_type_compatible<Tuple>(sequence_type{});
  258. else
  259. return false;
  260. }
  261. /// \brief Returns a key compatible to be used as the histogram key
  262. /// from the input tuple
  263. template <std::size_t... Dimensions, typename Tuple>
  264. key_t key_from_tuple(Tuple const& t) const
  265. {
  266. using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
  267. std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
  268. std::size_t const tuple_size = std::tuple_size<Tuple>::value;
  269. std::size_t const histogram_dimension = dimension();
  270. static_assert(
  271. ((index_list_size != 0 && index_list_size == histogram_dimension) ||
  272. (tuple_size == histogram_dimension)),
  273. "Tuple and histogram key of different sizes");
  274. using new_index_list = typename std::conditional
  275. <
  276. index_list_size == 0,
  277. boost::mp11::mp_list_c<std::size_t, 0>,
  278. index_list
  279. >::type;
  280. std::size_t const min =
  281. boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
  282. std::size_t const max =
  283. boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
  284. static_assert((0 <= min && max < tuple_size) || index_list_size == 0, "Index out of Range");
  285. using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
  286. using seq2 = boost::mp11::index_sequence<Dimensions...>;
  287. // TODO : Explore consequence of using if-constexpr
  288. using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
  289. auto key = detail::tuple_to_tuple(t, sequence_type{});
  290. static_assert(
  291. is_tuple_type_compatible<Tuple>(seq1{}),
  292. "Tuple type and histogram type not compatible.");
  293. return make_histogram_key(key, seq1{});
  294. }
  295. /// \brief Returns a histogram compatible key from the input pixel which
  296. /// can be directly used
  297. template <std::size_t... Dimensions, typename Pixel>
  298. key_t key_from_pixel(Pixel const& p) const
  299. {
  300. using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
  301. std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
  302. std::size_t const pixel_dimension = num_channels<Pixel>::value;
  303. std::size_t const histogram_dimension = dimension();
  304. static_assert(
  305. ((index_list_size != 0 && index_list_size == histogram_dimension) ||
  306. (index_list_size == 0 && pixel_dimension == histogram_dimension)) &&
  307. is_pixel_compatible(),
  308. "Pixels and histogram key are not compatible.");
  309. using new_index_list = typename std::conditional
  310. <
  311. index_list_size == 0,
  312. boost::mp11::mp_list_c<std::size_t, 0>,
  313. index_list
  314. >::type;
  315. std::size_t const min =
  316. boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
  317. std::size_t const max =
  318. boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
  319. static_assert(
  320. (0 <= min && max < pixel_dimension) || index_list_size == 0, "Index out of Range");
  321. using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
  322. using seq2 = boost::mp11::index_sequence<Dimensions...>;
  323. using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
  324. auto key = detail::pixel_to_tuple(p, sequence_type{});
  325. return make_histogram_key(key, seq1{});
  326. }
  327. /// \brief Return nearest smaller key to specified histogram key
  328. key_t nearest_key(key_t const& k) const
  329. {
  330. using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
  331. static_assert(
  332. boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
  333. "Keys are not comparable.");
  334. auto nearest_k = k;
  335. if (base_t::find(k) != base_t::end())
  336. {
  337. return nearest_k;
  338. }
  339. else
  340. {
  341. bool once = true;
  342. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  343. if (v.first <= k)
  344. {
  345. if (once)
  346. {
  347. once = !once;
  348. nearest_k = v.first;
  349. }
  350. else if (nearest_k < v.first)
  351. nearest_k = v.first;
  352. }
  353. });
  354. return nearest_k;
  355. }
  356. }
  357. /// \brief Fills the histogram with the input image view
  358. template <std::size_t... Dimensions, typename SrcView>
  359. void fill(
  360. SrcView const& srcview,
  361. std::size_t bin_width = 1,
  362. bool applymask = false,
  363. std::vector<std::vector<bool>> mask = {},
  364. key_t lower = key_t(),
  365. key_t upper = key_t(),
  366. bool setlimits = false)
  367. {
  368. gil_function_requires<ImageViewConcept<SrcView>>();
  369. using channel_t = typename channel_type<SrcView>::type;
  370. for (std::ptrdiff_t src_y = 0; src_y < srcview.height(); ++src_y)
  371. {
  372. auto src_it = srcview.row_begin(src_y);
  373. for (std::ptrdiff_t src_x = 0; src_x < srcview.width(); ++src_x)
  374. {
  375. if (applymask && !mask[src_y][src_x])
  376. continue;
  377. auto scaled_px = src_it[src_x];
  378. static_for_each(scaled_px, [&](channel_t& ch) {
  379. ch = ch / bin_width;
  380. });
  381. auto key = key_from_pixel<Dimensions...>(scaled_px);
  382. if (!setlimits ||
  383. (detail::tuple_compare(lower, key) && detail::tuple_compare(key, upper)))
  384. base_t::operator[](key)++;
  385. }
  386. }
  387. }
  388. /// \brief Can return a subset or a mask over the current histogram
  389. template <std::size_t... Dimensions, typename Tuple>
  390. histogram sub_histogram(Tuple const& t1, Tuple const& t2)
  391. {
  392. using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
  393. std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
  394. std::size_t const histogram_dimension = dimension();
  395. std::size_t const min =
  396. boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
  397. std::size_t const max =
  398. boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
  399. static_assert(
  400. (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
  401. "Index out of Range");
  402. using seq1 = boost::mp11::make_index_sequence<dimension()>;
  403. using seq2 = boost::mp11::index_sequence<Dimensions...>;
  404. static_assert(
  405. is_tuple_type_compatible<Tuple>(seq1{}),
  406. "Tuple type and histogram type not compatible.");
  407. auto low = make_histogram_key(t1, seq1{});
  408. auto low_key = detail::tuple_to_tuple(low, seq2{});
  409. auto high = make_histogram_key(t2, seq1{});
  410. auto high_key = detail::tuple_to_tuple(high, seq2{});
  411. histogram sub_h;
  412. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& k) {
  413. auto tmp_key = detail::tuple_to_tuple(k.first, seq2{});
  414. if (low_key <= tmp_key && tmp_key <= high_key)
  415. sub_h[k.first] += base_t::operator[](k.first);
  416. });
  417. return sub_h;
  418. }
  419. /// \brief Returns a sub-histogram over specified axes
  420. template <std::size_t... Dimensions>
  421. histogram<boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<Dimensions>>...> sub_histogram()
  422. {
  423. using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
  424. std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
  425. std::size_t const histogram_dimension = dimension();
  426. std::size_t const min =
  427. boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
  428. std::size_t const max =
  429. boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
  430. static_assert(
  431. (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
  432. "Index out of Range");
  433. histogram<boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<Dimensions>>...> sub_h;
  434. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  435. auto sub_key =
  436. detail::tuple_to_tuple(v.first, boost::mp11::index_sequence<Dimensions...>{});
  437. sub_h[sub_key] += base_t::operator[](v.first);
  438. });
  439. return sub_h;
  440. }
  441. /// \brief Normalize this histogram class
  442. void normalize()
  443. {
  444. double sum = 0.0;
  445. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  446. sum += v.second;
  447. });
  448. // std::cout<<(long int)sum<<"asfe";
  449. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  450. base_t::operator[](v.first) = v.second / sum;
  451. });
  452. }
  453. /// \brief Return the sum count of all bins
  454. double sum() const
  455. {
  456. double sum = 0.0;
  457. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  458. sum += v.second;
  459. });
  460. return sum;
  461. }
  462. /// \brief Return the minimum key in histogram
  463. key_t min_key() const
  464. {
  465. key_t min_key = base_t::begin()->first;
  466. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  467. if (v.first < min_key)
  468. min_key = v.first;
  469. });
  470. return min_key;
  471. }
  472. /// \brief Return the maximum key in histogram
  473. key_t max_key() const
  474. {
  475. key_t max_key = base_t::begin()->first;
  476. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  477. if (v.first > max_key)
  478. max_key = v.first;
  479. });
  480. return max_key;
  481. }
  482. /// \brief Return sorted keys in a vector
  483. std::vector<key_t> sorted_keys() const
  484. {
  485. std::vector<key_t> sorted_keys;
  486. std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
  487. sorted_keys.push_back(v.first);
  488. });
  489. std::sort(sorted_keys.begin(), sorted_keys.end());
  490. return sorted_keys;
  491. }
  492. private:
  493. template <typename Tuple, std::size_t... I>
  494. key_t make_histogram_key(Tuple const& t, boost::mp11::index_sequence<I...>) const
  495. {
  496. return std::make_tuple(
  497. static_cast<typename boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>>(
  498. std::get<I>(t))...);
  499. }
  500. template <typename Tuple, std::size_t... I>
  501. static constexpr bool is_tuple_type_compatible(boost::mp11::index_sequence<I...>)
  502. {
  503. using tp = boost::mp11::mp_list
  504. <
  505. typename std::is_convertible
  506. <
  507. boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>,
  508. typename std::tuple_element<I, Tuple>::type
  509. >::type...
  510. >;
  511. return boost::mp11::mp_all_of<tp, boost::mp11::mp_to_bool>::value;
  512. }
  513. template <typename Tuple>
  514. static constexpr bool is_tuple_size_compatible()
  515. {
  516. return (std::tuple_size<Tuple>::value == dimension());
  517. }
  518. };
  519. ///
  520. /// \fn void fill_histogram
  521. /// \ingroup Histogram Algorithms
  522. /// \tparam SrcView Input image view
  523. /// \tparam Container Input histogram container
  524. /// \brief Overload this function to provide support for boost::gil::histogram or
  525. /// any other external histogram
  526. ///
  527. /// Example :
  528. /// \code
  529. /// histogram<int> h;
  530. /// fill_histogram(view(img), h);
  531. /// \endcode
  532. ///
  533. template <typename SrcView, typename Container>
  534. void fill_histogram(SrcView const&, Container&);
  535. ///
  536. /// \fn void fill_histogram
  537. /// \ingroup Histogram Algorithms
  538. /// @param srcview Input Input image view
  539. /// @param hist Output Histogram to be filled
  540. /// @param bin_width Input Specify the bin widths for the histogram.
  541. /// @param accumulate Input Specify whether to accumulate over the values already present in h (default = false)
  542. /// @param sparsaefill Input Specify whether to have a sparse or continuous histogram (default = true)
  543. /// @param applymask Input Specify if image mask is to be specified
  544. /// @param mask Input Mask as a 2D vector. Used only if prev argument specified
  545. /// @param lower Input Lower limit on the values in histogram (default numeric_limit::min() on axes)
  546. /// @param upper Input Upper limit on the values in histogram (default numeric_limit::max() on axes)
  547. /// @param setlimits Input Use specified limits if this is true (default is false)
  548. /// \brief Overload version of fill_histogram
  549. ///
  550. /// Takes a third argument to determine whether to clear container before filling.
  551. /// For eg, when there is a need to accumulate the histograms do
  552. /// \code
  553. /// fill_histogram(view(img), hist, true);
  554. /// \endcode
  555. ///
  556. template <std::size_t... Dimensions, typename SrcView, typename... T>
  557. void fill_histogram(
  558. SrcView const& srcview,
  559. histogram<T...>& hist,
  560. std::size_t bin_width = 1,
  561. bool accumulate = false,
  562. bool sparsefill = true,
  563. bool applymask = false,
  564. std::vector<std::vector<bool>> mask = {},
  565. typename histogram<T...>::key_type lower =
  566. detail::tuple_limit<typename histogram<T...>::key_type>::min(),
  567. typename histogram<T...>::key_type upper =
  568. detail::tuple_limit<typename histogram<T...>::key_type>::max(),
  569. bool setlimits = false)
  570. {
  571. if (!accumulate)
  572. hist.clear();
  573. detail::filler<histogram<T...>::dimension()> f;
  574. if (!sparsefill)
  575. f(hist, lower, upper, bin_width);
  576. hist.template fill<Dimensions...>(srcview, bin_width, applymask, mask, lower, upper, setlimits);
  577. }
  578. ///
  579. /// \fn void cumulative_histogram(Container&)
  580. /// \ingroup Histogram Algorithms
  581. /// \tparam Container Input histogram container
  582. /// \brief Optionally overload this function with any external histogram class
  583. ///
  584. /// Cumulative histogram is calculated over any arbitrary dimensional
  585. /// histogram. The only tradeoff could be the runtime complexity which in
  586. /// the worst case would be max( #pixel_values , #bins ) * #dimensions.
  587. /// For single dimensional histograms the complexity has been brought down to
  588. /// #bins * log( #bins ) by sorting the keys and then calculating the cumulative version.
  589. ///
  590. template <typename Container>
  591. auto cumulative_histogram(Container const&) -> Container;
  592. template <typename... T>
  593. auto cumulative_histogram(histogram<T...> const& hist) -> histogram<T...>
  594. {
  595. using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
  596. static_assert(
  597. boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
  598. "Cumulative histogram not possible of this type");
  599. using histogram_t = histogram<T...>;
  600. using pair_t = std::pair<typename histogram_t::key_type, typename histogram_t::mapped_type>;
  601. using value_t = typename histogram_t::value_type;
  602. histogram_t cumulative_hist;
  603. std::size_t const dims = histogram_t::dimension();
  604. if (dims == 1)
  605. {
  606. std::vector<pair_t> sorted_keys(hist.size());
  607. std::size_t counter = 0;
  608. std::for_each(hist.begin(), hist.end(), [&](value_t const& v) {
  609. sorted_keys[counter++] = std::make_pair(v.first, v.second);
  610. });
  611. std::sort(sorted_keys.begin(), sorted_keys.end());
  612. auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
  613. for (std::size_t i = 0; i < sorted_keys.size(); ++i)
  614. {
  615. cumulative_counter += sorted_keys[i].second;
  616. cumulative_hist[(sorted_keys[i].first)] = cumulative_counter;
  617. }
  618. }
  619. else
  620. {
  621. std::for_each(hist.begin(), hist.end(), [&](value_t const& v1) {
  622. auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
  623. std::for_each(hist.begin(), hist.end(), [&](value_t const& v2) {
  624. bool comp = detail::tuple_compare(
  625. v2.first, v1.first,
  626. boost::mp11::make_index_sequence<histogram_t::dimension()>{});
  627. if (comp)
  628. cumulative_counter += hist.at(v2.first);
  629. });
  630. cumulative_hist[v1.first] = cumulative_counter;
  631. });
  632. }
  633. return cumulative_hist;
  634. }
  635. }} //namespace boost::gil
  636. #endif