Boost GIL


histogram.hpp
1 //
2 // Copyright 2020 Debabrata Mandal <mandaldebabrata123@gmail.com>
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 
9 #ifndef BOOST_GIL_HISTOGRAM_HPP
10 #define BOOST_GIL_HISTOGRAM_HPP
11 
12 #include <boost/gil/concepts/concept_check.hpp>
13 #include <boost/gil/metafunctions.hpp>
14 #include <boost/gil/pixel.hpp>
15 
16 #include <boost/mp11.hpp>
17 #include <boost/type_traits.hpp>
18 #include <boost/functional/hash.hpp>
19 
20 #include <array>
21 #include <iostream>
22 #include <tuple>
23 #include <utility>
24 #include <vector>
25 #include <type_traits>
26 #include <map>
27 #include <unordered_map>
28 
29 namespace boost { namespace gil {
30 
39 
40 namespace detail {
41 
44 
47 template <std::size_t Index, typename... T>
48 inline typename std::enable_if<Index == sizeof...(T), void>::type
49  hash_tuple_impl(std::size_t&, std::tuple<T...> const&)
50 {
51 }
52 
55 template <std::size_t Index, typename... T>
56 inline typename std::enable_if<Index != sizeof...(T), void>::type
57  hash_tuple_impl(std::size_t& seed, std::tuple<T...> const& t)
58 {
59  boost::hash_combine(seed, std::get<Index>(t));
60  hash_tuple_impl<Index + 1>(seed, t);
61 }
62 
72 template <typename... T>
73 struct hash_tuple
74 {
75  std::size_t operator()(std::tuple<T...> const& t) const
76  {
77  std::size_t seed = 0;
78  hash_tuple_impl<0>(seed, t);
79  return seed;
80  }
81 };
82 
86 template <typename Pixel, std::size_t... I>
87 auto pixel_to_tuple(Pixel const& p, boost::mp11::index_sequence<I...>)
88  -> decltype(std::make_tuple(p[I]...))
89 {
90  return std::make_tuple(p[I]...);
91 }
92 
96 template <typename Tuple, std::size_t... I>
97 auto tuple_to_tuple(Tuple const& t, boost::mp11::index_sequence<I...>)
98  -> decltype(std::make_tuple(std::get<I>(t)...))
99 {
100  return std::make_tuple(std::get<I>(t)...);
101 }
102 
105 template <typename Tuple, std::size_t... I>
106 bool tuple_compare(Tuple const& t1, Tuple const& t2, boost::mp11::index_sequence<I...>)
107 {
108  std::array<bool, std::tuple_size<Tuple>::value> comp_list;
109  comp_list = {std::get<I>(t1) <= std::get<I>(t2)...};
110  bool comp = true;
111  for (std::size_t i = 0; i < comp_list.size(); i++)
112  {
113  comp = comp & comp_list[i];
114  }
115  return comp;
116 }
117 
123 template <typename Tuple>
124 bool tuple_compare(Tuple const& t1, Tuple const& t2)
125 {
126  std::size_t const tuple_size = std::tuple_size<Tuple>::value;
127  auto index_list = boost::mp11::make_index_sequence<tuple_size>{};
128  return tuple_compare(t1, t2, index_list);
129 }
130 
135 template <typename Tuple>
137 {
138  static constexpr Tuple min()
139  {
140  return min_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
141  }
142  static constexpr Tuple max()
143  {
144  return max_impl(boost::mp11::make_index_sequence<std::tuple_size<Tuple>::value>{});
145  }
146 
147 private:
148  template <std::size_t... I>
149  static constexpr Tuple min_impl(boost::mp11::index_sequence<I...>)
150  {
151  return std::make_tuple(
152  std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::min()...);
153  }
154 
155  template <std::size_t... I>
156  static constexpr Tuple max_impl(boost::mp11::index_sequence<I...>)
157  {
158  return std::make_tuple(
159  std::numeric_limits<typename std::tuple_element<I, Tuple>::type>::max()...);
160  }
161 };
162 
170 template <std::size_t Dimension>
171 struct filler
172 {
173  template <typename Container, typename Tuple>
174  void operator()(Container&, Tuple&, Tuple&, std::size_t)
175  {
176  }
177 };
178 
181 template <>
182 struct filler<1>
183 {
184  template <typename Container, typename Tuple>
185  void operator()(Container& hist, Tuple& lower, Tuple& upper, std::size_t bin_width = 1)
186  {
187  for (auto i = std::get<0>(lower); static_cast<std::size_t>(std::get<0>(upper) - i) >= bin_width; i += bin_width)
188  {
189  hist(i / bin_width) = 0;
190  }
191  hist(std::get<0>(upper) / bin_width) = 0;
192  }
193 };
194 
195 } //namespace detail
196 
212 template <typename... T>
213 class histogram : public std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>
214 {
215  using base_t = std::unordered_map<std::tuple<T...>, double, detail::hash_tuple<T...>>;
216  using bin_t = boost::mp11::mp_list<T...>;
217  using key_t = typename base_t::key_type;
218  using mapped_t = typename base_t::mapped_type;
219  using value_t = typename base_t::value_type;
220 
221 public:
222  histogram() = default;
223 
225  static constexpr std::size_t dimension()
226  {
227  return std::tuple_size<key_t>::value;
228  }
229 
231  mapped_t& operator()(T... indices)
232  {
233  auto key = std::make_tuple(indices...);
234  std::size_t const index_dimension = std::tuple_size<std::tuple<T...>>::value;
235  std::size_t const histogram_dimension = dimension();
236  static_assert(histogram_dimension == index_dimension, "Dimensions do not match.");
237 
238  return base_t::operator[](key);
239  }
240 
243  template <typename OtherType>
244  bool equals(OtherType const& otherhist) const
245  {
246  bool check = (dimension() == otherhist.dimension());
247 
248  using other_value_t = typename OtherType::value_type;
249  std::for_each(otherhist.begin(), otherhist.end(), [&](other_value_t const& v) {
250  key_t key = key_from_tuple(v.first);
251  if (base_t::find(key) != base_t::end())
252  {
253  check = check & (base_t::at(key) == otherhist.at(v.first));
254  }
255  else
256  {
257  check = false;
258  }
259  });
260  return check;
261  }
262 
265  static constexpr bool is_pixel_compatible()
266  {
267  using bin_types = boost::mp11::mp_list<T...>;
268  return boost::mp11::mp_all_of<bin_types, std::is_arithmetic>::value;
269  }
270 
273  template <typename Tuple>
274  bool is_tuple_compatible(Tuple const&)
275  {
276  std::size_t const tuple_size = std::tuple_size<Tuple>::value;
277  std::size_t const histogram_size = dimension();
278  // TODO : Explore consequence of using if-constexpr
279  using sequence_type = typename std::conditional
280  <
281  tuple_size >= histogram_size,
282  boost::mp11::make_index_sequence<histogram_size>,
283  boost::mp11::make_index_sequence<tuple_size>
284  >::type;
285 
286  if (is_tuple_size_compatible<Tuple>())
287  return is_tuple_type_compatible<Tuple>(sequence_type{});
288  else
289  return false;
290  }
291 
294  template <std::size_t... Dimensions, typename Tuple>
295  key_t key_from_tuple(Tuple const& t) const
296  {
297  using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
298  std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
299  std::size_t const tuple_size = std::tuple_size<Tuple>::value;
300  std::size_t const histogram_dimension = dimension();
301 
302  static_assert(
303  ((index_list_size != 0 && index_list_size == histogram_dimension) ||
304  (tuple_size == histogram_dimension)),
305  "Tuple and histogram key of different sizes");
306 
307  using new_index_list = typename std::conditional
308  <
309  index_list_size == 0,
310  boost::mp11::mp_list_c<std::size_t, 0>,
311  index_list
312  >::type;
313 
314  std::size_t const min =
315  boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
316 
317  std::size_t const max =
318  boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
319 
320  static_assert((0 <= min && max < tuple_size) || index_list_size == 0, "Index out of Range");
321 
322  using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
323  using seq2 = boost::mp11::index_sequence<Dimensions...>;
324  // TODO : Explore consequence of using if-constexpr
325  using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
326 
327  auto key = detail::tuple_to_tuple(t, sequence_type{});
328  static_assert(
329  is_tuple_type_compatible<Tuple>(seq1{}),
330  "Tuple type and histogram type not compatible.");
331 
332  return make_histogram_key(key, seq1{});
333  }
334 
337  template <std::size_t... Dimensions, typename Pixel>
338  key_t key_from_pixel(Pixel const& p) const
339  {
340  using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
341  std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
342  std::size_t const pixel_dimension = num_channels<Pixel>::value;
343  std::size_t const histogram_dimension = dimension();
344 
345  static_assert(
346  ((index_list_size != 0 && index_list_size == histogram_dimension) ||
347  (index_list_size == 0 && pixel_dimension == histogram_dimension)) &&
348  is_pixel_compatible(),
349  "Pixels and histogram key are not compatible.");
350 
351  using new_index_list = typename std::conditional
352  <
353  index_list_size == 0,
354  boost::mp11::mp_list_c<std::size_t, 0>,
355  index_list
356  >::type;
357 
358  std::size_t const min =
359  boost::mp11::mp_min_element<new_index_list, boost::mp11::mp_less>::value;
360 
361  std::size_t const max =
362  boost::mp11::mp_max_element<new_index_list, boost::mp11::mp_less>::value;
363 
364  static_assert(
365  (0 <= min && max < pixel_dimension) || index_list_size == 0, "Index out of Range");
366 
367  using seq1 = boost::mp11::make_index_sequence<histogram_dimension>;
368  using seq2 = boost::mp11::index_sequence<Dimensions...>;
369  using sequence_type = typename std::conditional<index_list_size == 0, seq1, seq2>::type;
370 
371  auto key = detail::pixel_to_tuple(p, sequence_type{});
372  return make_histogram_key(key, seq1{});
373  }
374 
376  key_t nearest_key(key_t const& k) const
377  {
378  using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
379  static_assert(
380  boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
381  "Keys are not comparable.");
382  auto nearest_k = k;
383  if (base_t::find(k) != base_t::end())
384  {
385  return nearest_k;
386  }
387  else
388  {
389  bool once = true;
390  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
391  if (v.first <= k)
392  {
393  if (once)
394  {
395  once = !once;
396  nearest_k = v.first;
397  }
398  else if (nearest_k < v.first)
399  nearest_k = v.first;
400  }
401  });
402  return nearest_k;
403  }
404  }
405 
407  template <std::size_t... Dimensions, typename SrcView>
408  void fill(
409  SrcView const& srcview,
410  std::size_t bin_width = 1,
411  bool applymask = false,
412  std::vector<std::vector<bool>> mask = {},
413  key_t lower = key_t(),
414  key_t upper = key_t(),
415  bool setlimits = false)
416  {
417  gil_function_requires<ImageViewConcept<SrcView>>();
418  using channel_t = typename channel_type<SrcView>::type;
419 
420  for (std::ptrdiff_t src_y = 0; src_y < srcview.height(); ++src_y)
421  {
422  auto src_it = srcview.row_begin(src_y);
423  for (std::ptrdiff_t src_x = 0; src_x < srcview.width(); ++src_x)
424  {
425  if (applymask && !mask[src_y][src_x])
426  continue;
427  auto scaled_px = src_it[src_x];
428  static_for_each(scaled_px, [&](channel_t& ch) {
429  ch = ch / bin_width;
430  });
431  auto key = key_from_pixel<Dimensions...>(scaled_px);
432  if (!setlimits ||
433  (detail::tuple_compare(lower, key) && detail::tuple_compare(key, upper)))
434  base_t::operator[](key)++;
435  }
436  }
437  }
438 
440  template <std::size_t... Dimensions, typename Tuple>
441  histogram sub_histogram(Tuple const& t1, Tuple const& t2)
442  {
443  using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
444  std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
445  std::size_t const histogram_dimension = dimension();
446 
447  std::size_t const min =
448  boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
449 
450  std::size_t const max =
451  boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
452 
453  static_assert(
454  (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
455  "Index out of Range");
456 
457  using seq1 = boost::mp11::make_index_sequence<dimension()>;
458  using seq2 = boost::mp11::index_sequence<Dimensions...>;
459 
460  static_assert(
461  is_tuple_type_compatible<Tuple>(seq1{}),
462  "Tuple type and histogram type not compatible.");
463 
464  auto low = make_histogram_key(t1, seq1{});
465  auto low_key = detail::tuple_to_tuple(low, seq2{});
466  auto high = make_histogram_key(t2, seq1{});
467  auto high_key = detail::tuple_to_tuple(high, seq2{});
468 
469  histogram sub_h;
470  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& k) {
471  auto tmp_key = detail::tuple_to_tuple(k.first, seq2{});
472  if (low_key <= tmp_key && tmp_key <= high_key)
473  sub_h[k.first] += base_t::operator[](k.first);
474  });
475  return sub_h;
476  }
477 
479  template <std::size_t... Dimensions>
481  {
482  using index_list = boost::mp11::mp_list_c<std::size_t, Dimensions...>;
483  std::size_t const index_list_size = boost::mp11::mp_size<index_list>::value;
484  std::size_t const histogram_dimension = dimension();
485 
486  std::size_t const min =
487  boost::mp11::mp_min_element<index_list, boost::mp11::mp_less>::value;
488 
489  std::size_t const max =
490  boost::mp11::mp_max_element<index_list, boost::mp11::mp_less>::value;
491 
492  static_assert(
493  (0 <= min && max < histogram_dimension) && index_list_size < histogram_dimension,
494  "Index out of Range");
495 
497 
498  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
499  auto sub_key =
500  detail::tuple_to_tuple(v.first, boost::mp11::index_sequence<Dimensions...>{});
501  sub_h[sub_key] += base_t::operator[](v.first);
502  });
503  return sub_h;
504  }
505 
507  void normalize()
508  {
509  double sum = 0.0;
510  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
511  sum += v.second;
512  });
513  // std::cout<<(long int)sum<<"asfe";
514  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
515  base_t::operator[](v.first) = v.second / sum;
516  });
517  }
518 
520  double sum() const
521  {
522  double sum = 0.0;
523  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
524  sum += v.second;
525  });
526  return sum;
527  }
528 
530  key_t min_key() const
531  {
532  key_t min_key = base_t::begin()->first;
533  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
534  if (v.first < min_key)
535  min_key = v.first;
536  });
537  return min_key;
538  }
539 
541  key_t max_key() const
542  {
543  key_t max_key = base_t::begin()->first;
544  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
545  if (v.first > max_key)
546  max_key = v.first;
547  });
548  return max_key;
549  }
550 
552  std::vector<key_t> sorted_keys() const
553  {
554  std::vector<key_t> sorted_keys;
555  std::for_each(base_t::begin(), base_t::end(), [&](value_t const& v) {
556  sorted_keys.push_back(v.first);
557  });
558  std::sort(sorted_keys.begin(), sorted_keys.end());
559  return sorted_keys;
560  }
561 
562 private:
563  template <typename Tuple, std::size_t... I>
564  key_t make_histogram_key(Tuple const& t, boost::mp11::index_sequence<I...>) const
565  {
566  return std::make_tuple(
567  static_cast<typename boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>>(
568  std::get<I>(t))...);
569  }
570 
571  template <typename Tuple, std::size_t... I>
572  static constexpr bool is_tuple_type_compatible(boost::mp11::index_sequence<I...>)
573  {
574  using tp = boost::mp11::mp_list
575  <
576  typename std::is_convertible
577  <
578  boost::mp11::mp_at<bin_t, boost::mp11::mp_size_t<I>>,
579  typename std::tuple_element<I, Tuple>::type
580  >::type...
581  >;
582  return boost::mp11::mp_all_of<tp, boost::mp11::mp_to_bool>::value;
583  }
584 
585  template <typename Tuple>
586  static constexpr bool is_tuple_size_compatible()
587  {
588  return (std::tuple_size<Tuple>::value == dimension());
589  }
590 };
591 
606 template <typename SrcView, typename Container>
607 void fill_histogram(SrcView const&, Container&);
608 
630 template <std::size_t... Dimensions, typename SrcView, typename... T>
631 void fill_histogram(
632  SrcView const& srcview,
633  histogram<T...>& hist,
634  std::size_t bin_width = 1,
635  bool accumulate = false,
636  bool sparsefill = true,
637  bool applymask = false,
638  std::vector<std::vector<bool>> mask = {},
639  typename histogram<T...>::key_type lower =
640  detail::tuple_limit<typename histogram<T...>::key_type>::min(),
641  typename histogram<T...>::key_type upper =
642  detail::tuple_limit<typename histogram<T...>::key_type>::max(),
643  bool setlimits = false)
644 {
645  if (!accumulate)
646  hist.clear();
647 
648  detail::filler<histogram<T...>::dimension()> f;
649  if (!sparsefill)
650  f(hist, lower, upper, bin_width);
651 
652  hist.template fill<Dimensions...>(srcview, bin_width, applymask, mask, lower, upper, setlimits);
653 }
654 
667 template <typename Container>
668 Container cumulative_histogram(Container const&);
669 
670 template <typename... T>
671 histogram<T...> cumulative_histogram(histogram<T...> const& hist)
672 {
673  using check_list = boost::mp11::mp_list<boost::has_less<T>...>;
674  static_assert(
675  boost::mp11::mp_all_of<check_list, boost::mp11::mp_to_bool>::value,
676  "Cumulative histogram not possible of this type");
677 
678  using histogram_t = histogram<T...>;
679  using pair_t = std::pair<typename histogram_t::key_type, typename histogram_t::mapped_type>;
680  using value_t = typename histogram_t::value_type;
681 
682  histogram_t cumulative_hist;
683  std::size_t const dims = histogram_t::dimension();
684  if (dims == 1)
685  {
686  std::vector<pair_t> sorted_keys(hist.size());
687  std::size_t counter = 0;
688  std::for_each(hist.begin(), hist.end(), [&](value_t const& v) {
689  sorted_keys[counter++] = std::make_pair(v.first, v.second);
690  });
691  std::sort(sorted_keys.begin(), sorted_keys.end());
692  auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
693  for (std::size_t i = 0; i < sorted_keys.size(); ++i)
694  {
695  cumulative_counter += sorted_keys[i].second;
696  cumulative_hist[(sorted_keys[i].first)] = cumulative_counter;
697  }
698  }
699  else
700  {
701  std::for_each(hist.begin(), hist.end(), [&](value_t const& v1) {
702  auto cumulative_counter = static_cast<typename histogram_t::mapped_type>(0);
703  std::for_each(hist.begin(), hist.end(), [&](value_t const& v2) {
704  bool comp = detail::tuple_compare(
705  v2.first, v1.first,
706  boost::mp11::make_index_sequence<histogram_t::dimension()>{});
707  if (comp)
708  cumulative_counter += hist.at(v2.first);
709  });
710  cumulative_hist[v1.first] = cumulative_counter;
711  });
712  }
713  return cumulative_hist;
714 }
715 
716 }} //namespace boost::gil
717 
718 #endif
boost::gil::histogram::equals
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:244
boost::gil::histogram::key_from_pixel
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:338
boost::gil::histogram::min_key
key_t min_key() const
Return the minimum key in histogram.
Definition: histogram.hpp:530
boost::gil::detail::filler
Filler is used to fill the histogram class with all values between a specified range This functor is ...
Definition: histogram.hpp:171
boost::gil::histogram::max_key
key_t max_key() const
Return the maximum key in histogram.
Definition: histogram.hpp:541
boost::gil::detail::tuple_limit
Provides equivalent of std::numeric_limits for type std::tuple tuple_limit gets called with only tupl...
Definition: histogram.hpp:136
boost::gil::histogram::is_tuple_compatible
bool is_tuple_compatible(Tuple const &)
Checks if the histogram class is compatible to be used with the specified tuple type.
Definition: histogram.hpp:274
boost::gil::detail::tuple_compare
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:124
boost::gil::detail::pixel_to_tuple
auto pixel_to_tuple(Pixel const &p, boost::mp11::index_sequence< I... >) -> decltype(std::make_tuple(p[I]...))
Definition: histogram.hpp:87
boost::gil::histogram::normalize
void normalize()
Normalize this histogram class.
Definition: histogram.hpp:507
boost::gil::detail::hash_tuple
Functor provided for the hashing of tuples. The following approach makes use hash_combine from boost:...
Definition: histogram.hpp:73
boost::gil::histogram::sub_histogram
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:480
boost::gil::histogram::dimension
static constexpr std::size_t dimension()
Returns the number of dimensions(axes) the class supports.
Definition: histogram.hpp:225
boost::gil::histogram::sum
double sum() const
Return the sum count of all bins.
Definition: histogram.hpp:520
boost::gil::histogram::key_from_tuple
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:295
boost::gil::histogram::fill
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:408
boost::gil::histogram::nearest_key
key_t nearest_key(key_t const &k) const
Return nearest smaller key to specified histogram key.
Definition: histogram.hpp:376
std::fill
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:365
boost::gil::histogram::operator()
mapped_t & operator()(T... indices)
Returns bin value corresponding to specified tuple.
Definition: histogram.hpp:231
boost::gil::histogram::is_pixel_compatible
static constexpr bool is_pixel_compatible()
Checks if the histogram class is compatible to be used with a GIL image type.
Definition: histogram.hpp:265
boost::gil::histogram::sorted_keys
std::vector< key_t > sorted_keys() const
Return sorted keys in a vector.
Definition: histogram.hpp:552
boost::gil::histogram::sub_histogram
histogram sub_histogram(Tuple const &t1, Tuple const &t2)
Can return a subset or a mask over the current histogram.
Definition: histogram.hpp:441
boost::gil::channel_type
Definition: color_convert.hpp:31
boost::gil::num_channels
Returns the number of channels of a pixel-based GIL construct.
Definition: locator.hpp:38
boost::gil::histogram
Default histogram class provided by boost::gil.
Definition: histogram.hpp:213
boost::gil::detail::tuple_to_tuple
auto tuple_to_tuple(Tuple const &t, boost::mp11::index_sequence< I... >) -> decltype(std::make_tuple(std::get< I >(t)...))
Definition: histogram.hpp:97