libcrn  3.9.5
A document image processing library
•All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNHistogram.cpp
Go to the documentation of this file.
1 /* Copyright 2006-2016 Yann LEYDIER, INSA-Lyon, CoReNum, Université Paris Descartes, ENS-Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: SHistogram cpp
19  * \author Yann LEYDIER, Jean DUONG, Asma OUJI, Frank LeBOURGEOIS
20  */
21 
23 #include <CRNData/CRNData.h>
24 #include <CRNException.h>
25 #include <CRNImage/CRNImageBW.h>
26 #include <CRNData/CRNDataFactory.h>
27 #include <CRNIO/CRNIO.h>
28 #include <functional>
29 #include <CRNi18n.h>
30 
31 using namespace crn;
32 
33 /*****************************************************************************/
42 Histogram::Histogram(size_t s, unsigned int v):
43  bins(s, v),
44  compression(1)
45 { }
46 
47 /*****************************************************************************/
56 Histogram::Histogram(const Histogram &src, unsigned int c):
57  compression(c)
58 {
59 
60  if (c == 1)
61  {
62  bins = src.bins;
63  }
64  else
65  {
66  size_t q = src.Size() / compression;
67  size_t r = src.Size() % compression;
68  size_t newsize;
69  if (r > 0)
70  {
71  newsize = q + 1;
72  }
73  else
74  {
75  newsize = q;
76  }
77 
78  datatype(newsize, 0).swap(bins);
79  size_t k = 0;
80 
81  for (size_t i = 0; i < q; i++)
82  {
83  unsigned int sum = 0;
84 
85  for (unsigned int j = 0; j < c; j++)
86  {
87  sum += src.bins[k];
88  k++;
89  }
90 
91  bins[i] = sum;
92  }
93 
94  if (r > 0)
95  {
96  unsigned int sum = 0;
97 
98  for (size_t j = k; j < src.Size(); j++)
99  {
100  sum += src.bins[k];
101  k++;
102  }
103 
104  bins[q] = sum;
105  }
106  }
107 }
108 
109 /*****************************************************************************/
120 void Histogram::SetBin(size_t k, unsigned int v)
121 {
122  if (k >= bins.size())
123  {
124  throw ExceptionDomain(StringUTF8("Histogram::SetBin(size_t k, unsigned int v): ") +
125  _("invalid index."));
126  }
127 
128  bins[k] = v;
129 }
130 
131 /*****************************************************************************/
142 void Histogram::IncBin(size_t k, unsigned int i)
143 {
144  if (k >= bins.size())
145  {
146  throw ExceptionDomain(StringUTF8("Histogram::IncBin(size_t k, unsigned int i): ") +
147  _("invalid index."));
148  }
149 
150  bins[k] += i;
151 }
152 
153 /*****************************************************************************/
165 unsigned int Histogram::GetBin(size_t k) const
166 {
167  if (k >= bins.size())
168  {
169  throw ExceptionDomain(StringUTF8("Histogram::GetBin(size_t k): ") +
170  _("invalid index."));
171  }
172 
173  return bins[k];
174 }
175 
176 
177 /*****************************************************************************/
185 unsigned int Histogram::CumulateBins() const
186 {
187  unsigned int Cumul = 0;
188 
189  for (auto & elem : bins)
190  {
191  Cumul += elem;
192  }
193 
194  return Cumul;
195 }
196 
197 /*****************************************************************************/
205 double Histogram::Mean() const
206 {
207  double m = 0.0;
208  unsigned int p = 0;
209 
210  for (size_t k = 0; k < bins.size(); k++)
211  {
212  m += double(k * bins[k]);
213  p += bins[k];
214  }
215 
216  m /= p;
217 
218  return m;
219 }
220 
221 /*****************************************************************************/
231 double Histogram::Variance(double m) const
232 {
233  double v = 0.0;
234  unsigned int p=0;
235 
236  for (size_t k = 0; k < bins.size(); k++)
237  {
238  double d = double(k) - m;
239 
240  v += d * d * bins[k];
241  p += bins[k];
242  }
243 
244  v /= p;
245 
246  return v;
247 }
248 
249 /*****************************************************************************/
257 double Histogram::Variance() const
258 {
259  double m = Mean();
260  double v = 0.0;
261  unsigned int p=0;
262 
263  for (size_t k = 0; k < bins.size(); k++)
264  {
265  double d = double(k) - m;
266 
267  v += d * d * bins[k];
268  p += bins[k];
269  }
270 
271  v /= p;
272 
273  return v;
274 }
275 
276 /*****************************************************************************/
284 unsigned int Histogram::Max() const
285 {
286  unsigned int m = 0;
287 
288  for (auto & elem : bins)
289  {
290  m = crn::Max(m, elem);
291  }
292 
293  return m;
294 }
295 
296 /*****************************************************************************/
304 unsigned int Histogram::Min() const
305 {
306  unsigned int m = bins[0];
307 
308  for (auto & elem : bins)
309  {
310  m = crn::Min(m, elem);
311  }
312 
313  return m;
314 }
315 
316 /*****************************************************************************/
324 size_t Histogram::Argmax() const
325 {
326  unsigned int m = 0;
327  size_t a = 0;
328 
329  for (size_t k = 0; k < bins.size(); k++)
330  {
331  unsigned int v = bins[k];
332 
333  if (v > m)
334  {
335  m = bins[k];
336  a = k;
337  }
338  }
339 
340  return a;
341 }
342 
343 /*****************************************************************************/
351 size_t Histogram::Argmin() const
352 {
353  unsigned int m = bins[0];
354  size_t a = 0;
355 
356  for (size_t k = 0; k < bins.size(); k++)
357  {
358  unsigned int v = bins[k];
359 
360  if (v < m)
361  {
362  m = bins[k];
363  a = k;
364  }
365  }
366 
367  return a;
368 }
369 
370 /*****************************************************************************/
378 void Histogram::SetCeiling(unsigned int m)
379 {
380  for (auto & elem : bins)
381  {
382  elem = crn::Min(m,elem);
383 
384  }
385 }
386 
387 /*****************************************************************************/
395 void Histogram::ScaleMaxTo(unsigned int m)
396 {
397  unsigned int c = Max(); /* Maximal value for this histogram */
398 
399  if (c == 0)
400  {
401  CRNWarning(String(U"Histogram::ScaleMaxTo(int m): ") +
402  _("flat histogram."));
403  return;
404  }
405 
406  double s = (double) m / (double) c; /* Scale factor */
407 
408  for (auto & elem : bins)
409  {
410  unsigned int v = (unsigned int)(elem * s);
411 
412  elem = v;
413  }
414 }
415 
416 /*****************************************************************************/
426 {
427  datatype H(bins.size());
428 
429  for (size_t k = 0; k < bins.size(); k++)
430  {
431  int left = crn::Max(0, int(k) - int(d));
432  int right = crn::Min(int(bins.size()) - 1, int(k) + int(d));
433 
434  uint64_t m = 0;
435  uint64_t n = right - left + 1;
436 
437  for (int j = left; j <= right; j++)
438  {
439  m += bins[j];
440  }
441 
442  H[k] = (unsigned int)(m / n);
443  }
444 
445  bins.swap(H);
446 }
447 
448 /*****************************************************************************/
458 {
459  if (d > bins.size())
460  {
461  CRNWarning(String(U"Histogram::CircularAverageSmoothing(size_t d): ") +
462  _("window larger than histogram. Cropping."));
463  d = bins.size(); // wew, dirty !
464  }
465 
466  datatype H(bins.size());
467 
468  for (size_t k = 0; k < bins.size(); k++)
469  {
470  int left = int(k) - int(d);
471  int right = int(k + d);
472  double m = 0.0;
473  double n = double(right) - double(left) + 1;
474 
475  for (int j = left; j <= right; j++)
476  {
477  int index = j;
478  if (index < 0) index = int(bins.size()) + index;
479  if (index >= int(bins.size())) index -= int(bins.size());
480  m += (double) bins[index] / n;
481  }
482 
483  H[k]=(unsigned int)m;
484  }
485 
486  bins.swap(H);
487 }
488 
489 /*****************************************************************************/
497 std::vector<size_t> Histogram::Modes() const
498 {
499  std::vector<size_t> modes;
500  if (bins.empty())
501  return modes;
502  if (bins.size() == 1)
503  {
504  modes.push_back(0);
505  return modes;
506  }
507  // first value is a mode ?
508  if (bins[0] > bins[1])
509  modes.push_back(0);
510  for (size_t b = 1; b < bins.size() - 1; ++b)
511  {
512  if (bins[b] > bins[b - 1])
513  { // increasing
514  size_t first = b;
515  if (bins[b] < bins[b + 1])
516  { // still increasing, pass
517  continue;
518  }
519  while (bins[b] == bins[b + 1])
520  { // plateau
521  b += 1;
522  if (b == bins.size() - 1)
523  { // reached the end of the histogram
524  modes.push_back((first + bins.size() - 1) / 2);
525  break;
526  }
527  else if (b == bins.size() - 2)
528  { // reached the penultimate
529  if (bins[b] == bins[b + 1])
530  { // plateau till the end
531  modes.push_back((first + bins.size() - 1) / 2);
532  }
533  if (bins[b] > bins[b + 1])
534  { // peak
535  modes.push_back((first + b) / 2);
536  }
537  break;
538  }
539  }
540  if ((b < bins.size() - 1) && (bins[b] > bins[b + 1]))
541  { // peak !
542  modes.push_back((first + b) / 2);
543  }
544  }
545  }
546  if (bins[bins.size() - 2] < bins[bins.size() - 1])
547  modes.push_back(bins.size() - 1);
548 
549  return modes;
550 }
551 
560 std::vector<size_t> Histogram::StableModes() const
561 {
562  // copy histogram
563  Histogram s(*this);
564 
565  std::map<size_t, size_t> mcount; // key = number of modes, value = number of occurrences
566  std::map<size_t, std::vector<size_t> > msum; // key = number of modes, value = sum of the modes
567 
568  std::vector<size_t> modes(s.Modes());
569  size_t nmodes = modes.size();
570  size_t niter = 0;
571  while (nmodes > 1)
572  {
573  auto cit = mcount.find(nmodes);
574  if (cit != mcount.end())
575  { // update
576  cit->second += 1;
577  auto sit = msum.find(nmodes);
578  std::transform(sit->second.begin(), sit->second.end(), modes.begin(), sit->second.begin(), std::plus<size_t>());
579  }
580  else
581  { // add
582  mcount.insert(std::make_pair(nmodes, 1));
583  msum.insert(std::make_pair(nmodes, modes));
584  }
585  // smooth
586  s.AverageSmoothing(1);
587  modes = s.Modes();
588  nmodes = modes.size();
589  niter += 1;
590  }
591 
592  // if there is only one iteration, then it means there is only one mode
593  if (niter == 1)
594  {
595  return modes;
596  }
597 
598  // look for most stable mode number
599  nmodes = 0;
600  size_t maxpop = 0;
601  for (auto & elem : mcount)
602  {
603  if (elem.second > maxpop)
604  {
605  maxpop = elem.second;
606  nmodes = elem.first;
607  }
608  }
609 
610  // compute the vector of modes
611  if (nmodes == 0)
612  return std::vector<size_t>();
613 
614  modes.swap(msum[nmodes]);
615  std::transform(modes.begin(), modes.end(), modes.begin(), std::bind2nd(std::divides<size_t>(), maxpop));
616  return modes;
617 }
618 
619 /*****************************************************************************/
630 {
631  if (bins.size() != h.Size())
632  {
633  throw ExceptionDimension(StringUTF8("Histogram::Intersection(const Histogram &h): ") +
634  _("histograms must have same size."));
635  }
636 
637  Histogram i(bins.size());
638 
639  for (size_t k = 0; k < bins.size(); k++)
640  {
641  i.bins[k] = (unsigned int)(crn::Min(h.GetBin(k),bins[k]));
642  }
643 
644  return i;
645 }
646 
647 /*****************************************************************************/
658 {
659  if (bins.size() != h.Size())
660  {
661  throw ExceptionDomain(StringUTF8("Histogram::IntersectionDivergence("
662  "const Histogram &h): ") + _("histograms must have same size."));
663  }
664 
665  double cumulMin = 0.0;
666  double cumulH = h.CumulateBins();
667 
668  for (size_t k = 0; k < bins.size(); k++)
669  {
670  cumulMin += crn::Min(h.GetBin(k),bins[k]);
671  }
672 
673  return (1.0 - (cumulMin / cumulH));
674 }
675 
676 /*****************************************************************************/
686 double Histogram::Correlation(const Histogram &h) const
687 {
688  if (bins.size() != h.Size())
689  {
690  throw ExceptionDimension(StringUTF8("Histogram::Correlation("
691  "const Histogram &h): ") + _("histograms must have same size."));
692  }
693 
694  int offset_1 = (int)(CumulateBins() / bins.size());
695  int offset_2 = (int)(h.CumulateBins() / bins.size());
696 
697  double cumul_numer = 0.0;
698  double cumul_denom_1 = 0.0;
699  double cumul_denom_2 = 0.0;
700 
701  for (size_t k = 0; k < bins.size(); k++)
702  {
703  int v_1 = int(bins[k]) - offset_1;
704  int v_2 = int(h.bins[k]) - offset_2;
705 
706  cumul_numer += v_1 * v_2;
707  cumul_denom_1 += v_1 * v_1;
708  cumul_denom_2 += v_2 * v_2;
709  }
710 
711  cumul_numer /= sqrt(cumul_denom_1);
712  cumul_numer /= sqrt(cumul_denom_2);
713 
714  return cumul_numer;
715 }
716 
717 
718 /*****************************************************************************/
728 double Histogram::Chi2(const Histogram &h) const
729 {
730  if (bins.size() != h.Size())
731  {
732  throw ExceptionDimension(StringUTF8("Histogram::IntersectionDivergence("
733  "const Histogram &h): ") + _("histograms must have same size."));
734  return HUGE_VAL;
735  }
736 
737  double cumul_numer = 0.0;
738  double cumul_denom = 0.0;
739 
740  for (size_t k = 0; k < bins.size(); k++)
741  {
742  auto v_1 = int(bins[k]);
743  auto v_2 = int(h.bins[k]);
744  int diff = v_1 - v_2;
745 
746  cumul_numer += diff * diff;
747  cumul_denom += v_1 + v_2;
748  }
749 
750  return cumul_numer / cumul_denom;
751 }
752 
753 /*****************************************************************************/
766 double Histogram::MinkowskiDistance(const Histogram &h, double r) const
767 {
768  if (bins.size() != h.Size())
769  {
770  throw ExceptionDimension(StringUTF8("Histogram::MinkowskiDistance("
771  "const Histogram &h, double r): ") +
772  _("histograms must have same size."));
773  }
774 
775  double cumul = 0.0;
776  double invR = 1.0 / (double)(r);
777 
778  for (size_t k = 0; k < bins.size(); k++)
779  {
780  cumul += pow(fabs((double)(h.GetBin(k)) - (double)(bins[k])),r);
781  }
782 
783  return pow(cumul, invR);
784 }
785 
786 /*****************************************************************************/
799 {
800  if (bins.size() != h.Size())
801  {
802  throw ExceptionDimension(StringUTF8("Histogram::JeffreyDistance(const Histogram &h): ") +
803  _("histograms must have same size."));
804  }
805 
806  double cumul = 0.0;
807 
808  for (size_t k = 0; k < bins.size(); k++)
809  {
810  double h1 = bins[k];
811  double h2 = h.GetBin(k);
812  double m = (h1 + h2) / 2.0;
813 
814  cumul += h1 * log(h1 / m) + h2 * log(h2 / m);
815  }
816 
817  return cumul;
818 }
819 
820 /*****************************************************************************/
832 double Histogram::MatchDistance(const Histogram &h) const
833 {
834  if (bins.size() != h.Size())
835  {
836  throw ExceptionDimension(StringUTF8("Histogram::MatchDistance(const Histogram &h): ") +
837  _("histograms must have same size."));
838  }
839 
840  double cumul = 0.0;
841  double cumulH1 = 0.0;
842  double cumulH2 = 0.0;
843 
844  for (size_t k = 0; k < bins.size(); k++)
845  {
846  cumulH1 += bins[k];
847  cumulH2 += h.GetBin(k);
848  cumul += fabs(cumulH1 - cumulH2);
849  }
850 
851  return cumul;
852 }
853 
854 /*****************************************************************************/
867 {
868  if (bins.size() != h.Size())
869  {
870  throw ExceptionDimension(StringUTF8("Histogram::KolmogorovSmirnovDistance("
871  "const Histogram &h): ")+ _("histograms must have same size."));
872  }
873 
874  double max = 0.0;
875  double cumulH1 = 0.0;
876  double cumulH2 = 0.0;
877 
878  for (size_t k = 0; k < bins.size(); k++)
879  {
880  cumulH1 += bins[k];
881  cumulH2 += h.GetBin(k);
882  double diff = fabs(cumulH1 - cumulH2);
883 
884  if (diff > max)
885  {
886  max = diff;
887  }
888  }
889 
890  return max;
891 }
892 
901 double Histogram::EMD(const Histogram &h) const
902 {
903  if (bins.size() != h.Size())
904  {
905  throw ExceptionDimension(StringUTF8("Histogram::EMD(const Histogram &h): ")+ _("histograms must have same size."));
906  }
907  auto h1 = *this;
908  h1.Cumulate();
909  auto h2 = h;
910  h2.Cumulate();
911  auto dist = 0.0;
912  for (auto tmp : crn::Range(h1))
913  dist += double(Abs(int(h1[tmp]) - int(h2[tmp])));
914  return dist / double(h1.Size());
915 }
916 
925 double Histogram::CEMD(const Histogram &h) const
926 {
927  if (bins.size() != h.Size())
928  {
929  throw ExceptionDimension(StringUTF8("Histogram::CEMD(const Histogram &h): ")+ _("histograms must have same size."));
930  }
931  auto dist = std::numeric_limits<double>::max();
932  // compute EMD for each possible cumulative histogram
933  for (auto k : crn::Range(h))
934  {
935  // compute cumulative histogram
936  auto h1 = Histogram(Size());
937  auto h2 = Histogram(Size());
938  // sum from k to end
939  auto sum1 = 0u;
940  auto sum2 = 0u;
941  for (auto i = k; i < Size(); ++i)
942  {
943  sum1 += (*this)[i];
944  sum2 += h[i];
945  }
946  // cumulate from k to end and 0 to i (i < k)
947  for (auto i = size_t(0); i < k; ++i)
948  {
949  h1[i] = sum1;
950  h2[i] = sum2;
951  for (auto j = size_t(0); j <= i; ++j)
952  {
953  h1[i] += (*this)[j];
954  h2[i] += h[j];
955  }
956  }
957  // cumulate from k to i (i >= k)
958  for (auto i = k; i < Size(); ++i)
959  for (auto j = k; j <= i; ++j)
960  {
961  h1[i] += (*this)[j];
962  h2[i] += h[j];
963  }
964  // compute EMPD
965  auto d = 0.0;
966  for (auto tmp : crn::Range(h1))
967  d += double(Abs(int(h1[tmp]) - int(h2[tmp])));
968  // keep min
969  if (d < dist)
970  dist = d;
971  }
972  return dist / double(Size());
973 }
974 
975 /*****************************************************************************/
982 { }
983 
984 /*****************************************************************************/
993 {
994  bins.insert(bins.end(), h.bins.begin(), h.bins.end());
995 }
996 
997 /*****************************************************************************/
1009 void Histogram::Resize(size_t newsize)
1010 {
1011  if (newsize == 0)
1012  throw crn::ExceptionDomain(_("Cannot resize histogram with null size."));
1013 
1014  if (newsize == bins.size())
1015  return;
1016 
1017  datatype newbins(newsize);
1018 
1019  double ratio = (double)bins.size() / (double)newsize;
1020  double begin = 0;
1021  for (size_t tmp = 0; tmp < newsize; tmp++)
1022  {
1023  double val = 0;
1024  auto end = double(tmp + 1) * ratio;
1025  if (end >= double(bins.size())) end = double(bins.size()) - 0.0001; // yay... -_-
1026  double tb = begin;
1027  while (floor(tb) != floor(end))
1028  {
1029  double te = ceil(tb);
1030  if (te == tb) te += 1;
1031  val += (te - tb) * bins[(size_t)floor(tb)];
1032  tb = te;
1033  }
1034  val += (end - tb) * bins[(size_t)floor(tb)];
1035  if ((end - begin) != 0)
1036  val /= (end - begin);
1037  //GET: using round in place of direct cast
1038  //GETnewbins[tmp] = (unsigned int)val;
1039  newbins[tmp] = (unsigned int)round(val);
1040  begin = end;
1041  }
1042 
1043  bins.swap(newbins);
1044 }
1045 
1046 /*****************************************************************************/
1060 {
1061  bins.clear();
1062  if (el.GetValue() != "Histogram")
1063  {
1064  throw ExceptionInvalidArgument(StringUTF8("bool Histogram::deserialize(xml::Element &el): ") +
1065  _("Wrong XML element."));
1066  }
1067  xml::Node n(el.GetFirstChild());
1068  if (!n)
1069  {
1070  throw ExceptionNotFound(StringUTF8("bool Histogram::deserialize(xml::Element &el): ") +
1071  _("Cannot get CDATA."));
1072  }
1073  xml::Text t = n.AsText(); // may throw
1074  auto v = Data::ASCII85Decode<unsigned int>(t.GetValue());
1075  if (v.empty())
1076  {
1077  throw ExceptionRuntime(StringUTF8("bool Histogram::deserialize(xml::Element &el): ") +
1078  _("Cannot convert CDATA."));
1079  }
1080  bins.swap(v);
1081 }
1082 
1083 /*****************************************************************************/
1094 {
1095  xml::Element el(parent.PushBackElement("Histogram"));
1096  auto text = Data::ASCII85Encode(reinterpret_cast<const uint8_t * const>(bins.data()), bins.size() * sizeof(datatype::value_type));
1097  xml::Text t(el.PushBackText(text, false));
1098 
1099  return el;
1100 }
1101 
1108 {
1109  String s(U"Histogram: ");
1110  for (auto & elem : bins)
1111  {
1112  s += elem;
1113  s += U" ";
1114  }
1115  return s;
1116 }
1117 
1118 /*****************************************************************************/
1128 ImageBW Histogram::MakeImageBW(size_t height) const
1129 {
1130  auto bw = ImageBW(bins.size(), height, pixel::BWWhite);
1131  auto val = double(height) / double(Max());
1132  for (size_t k = 0; k < bins.size(); k++)
1133  {
1134  auto bin = GetBin(k);
1135  for (int i = 0; i < int(double(bin) * val) - 1; ++i)
1136  {
1137  bw.At(k, height - 1 - i) = pixel::BWBlack;
1138  }
1139  }
1140  return bw;
1141 }
1142 
1147 {
1148  unsigned int sum = 0;
1149  for (size_t k = 0; k < bins.size(); k++)
1150  {
1151  sum += GetBin(k);
1152  SetBin(k, sum);
1153  }
1154 }
1155 
1156 /*****************************************************************************/
1167 {
1168  Rect r;
1169  double factor = crn::Twice(M_PI) / double(bins.size());
1170  double max = Max();
1171  for (size_t tmp = 0; tmp < bins.size(); tmp++)
1172  {
1173  double tx = double(GetBin(tmp) * radius) / max * cos(double(tmp) * factor);
1174  double ty = double(GetBin(tmp) * radius) / max * sin(double(tmp) * factor);
1175  r |= Rect((int)tx, (int)ty);
1176  }
1177  if (!r.GetWidth() || !r.GetHeight())
1178  return ImageBW{};
1179  ImageBW img = ImageBW(r.GetWidth(), r.GetHeight(), pixel::BWWhite);
1180  for (size_t tmp = 0; tmp < bins.size(); tmp++)
1181  {
1182  double tx = double(GetBin(tmp) * radius) / max * cos(double(tmp) * factor);
1183  double ty = double(GetBin(tmp) * radius) / max * sin(double(tmp) * factor);
1184  img.DrawLine(-r.GetLeft(), -r.GetTop(), (int)tx - r.GetLeft(),
1185  (int)ty - r.GetTop(), pixel::BWBlack);
1186  }
1187  return img;
1188 }
1189 
1190 /*****************************************************************************/
1198 size_t Histogram::Fisher() const
1199 {
1200  std::vector<bool> notempty(bins.size());
1201  std::vector<double> tab(bins.size());
1202 
1203  for (size_t tmp = 0; tmp < bins.size(); tmp++)
1204  {
1205  if (bins[tmp] > 0)
1206  {
1207  notempty[tmp] = true;
1208  tab[tmp] = double((tmp + 1) * bins[tmp]);
1209  }
1210  else
1211  {
1212  notempty[tmp] = false;
1213  tab[tmp] = 0;
1214  }
1215  }
1216 
1217  double s1 = 0, s2 = 0;
1218  long n1 = 0, n2 = 0;
1219  for (size_t tmp = 0; tmp < bins.size(); tmp++)
1220  {
1221  if (notempty[tmp])
1222  {
1223  s2 += tab[tmp];
1224  n2 += bins[tmp];
1225  }
1226  }
1227  size_t index = 0;
1228  double f(0.0);
1229  do
1230  {
1231  if (notempty[index])
1232  {
1233  s1 += tab[index];
1234  n1 += bins[index];
1235  s2 -= tab[index];
1236  n2 -= bins[index];
1237  }
1238  if ((n1 * n2) == 0)
1239  f = -20.0;
1240  else
1241  f = double(index) - ((s1 / double(n1)) + (s2 / double(n2))) / 2.0;
1242  index += 1;
1243  } while ((index < bins.size()) && (f <= 0.0));
1244 
1245  if (index)
1246  return index - 1;
1247  else
1248  return 0;
1249 }
1250 
1251 /*****************************************************************************/
1260 {
1261  std::vector<double> entropy(bins.size());
1262  for (size_t tmp = 0; tmp < bins.size(); tmp++)
1263  {
1264  if (bins[tmp])
1265  entropy[tmp] = bins[tmp] * log((double)bins[tmp]);
1266  else
1267  entropy[tmp] = 0;
1268  }
1269  double max = 0;
1270  size_t thresh = 0;
1271  for (size_t t = 0; t < bins.size(); t++)
1272  {
1273  double s1 = 0, s2 = 0, n1 = 0, n2 = 0;
1274  for (size_t tmp = 0; tmp <= t; tmp++)
1275  if (bins[tmp])
1276  {
1277  s1 += entropy[tmp];
1278  n1 += bins[tmp];
1279  }
1280  for (size_t tmp = t + 1; tmp < bins.size(); tmp++)
1281  if (bins[tmp])
1282  {
1283  s2 += entropy[tmp];
1284  n2 += bins[tmp];
1285  }
1286  double en = 0;
1287  if ((n1 * n2) != 0)
1288  en = -(s1/n1) - (s2/n2) + log(n1*n2);
1289  if (en > max)
1290  {
1291  max = en;
1292  thresh = t;
1293  }
1294  }
1295  return thresh;
1296 }
1297 
1298 /*****************************************************************************/
1299 
1308 double Histogram::Entropy() const
1309 {
1310  auto e = 0.0;
1311  auto c = double(CumulateBins());
1312 
1313  for (auto & elem : bins)
1314  {
1315  auto b_k = double(elem);
1316 
1317  if (b_k != 0)
1318  {
1319  auto p_k = double(b_k / c);
1320 
1321  e += p_k * log(p_k);
1322  }
1323  }
1324 
1325  return -e;
1326 }
1327 
1328 /*****************************************************************************/
1329 
1338 {
1339  if (bins.empty())
1340  throw ExceptionUninitialized(_("The histogram is empty."));
1341  unsigned int mid = CumulateBins() / 2;
1342  unsigned int sum = 0;
1343  size_t index;
1344  for (index = 0; index < bins.size(); index++)
1345  {
1346  sum += bins[index];
1347  if (sum >= mid)
1348  break;
1349  }
1350  return index;
1351 }
1352 
1361 {
1362  Histogram poph(Max() + 1);
1363  for (auto & elem : bins)
1364  {
1365  poph.IncBin(elem);
1366  }
1367  return poph;
1368 }
1369 
1371  CRN_DATA_FACTORY_REGISTER(U"Histogram", Histogram)
1372  Cloner::Register<Histogram>();
1373  Ruler::Register<Histogram>();
1374 CRN_END_CLASS_CONSTRUCTOR(Histogram)
1375 
virtual StringUTF8 GetValue() const override
Gets the content of the node.
Definition: CRNXml.cpp:888
Image< pixel::BW > ImageBW
Black and white image class.
xml::Element Serialize(xml::Element &parent) const
Dumps the object to an XML element. Unsafe.
ScalarRange< T > Range(T b, T e)
Creates a range [[b, e[[.
Definition: CRNType.h:257
double JeffreyDivergence(const Histogram &h) const
Jeffrey divergence between two histograms.
double Entropy() const
the entropy
double IntersectionDivergence(const Histogram &h) const
Intersection divergence between two histograms.
void Deserialize(xml::Element &el)
Initializes the object from an XML element. Unsafe.
XML element.
Definition: CRNXml.h:135
A generic runtime error.
Definition: CRNException.h:131
void CircularAverageSmoothing(size_t d)
Smoothing circular histogram.
#define _(String)
Definition: CRNi18n.h:51
double KolmogorovSmirnovDistance(const Histogram &h) const
Kolmogorov-Smirnov distance between two histograms.
void IncBin(size_t k, unsigned int i=1u)
Increments a bin value.
const T & Max(const T &a, const T &b)
Returns the max of two values.
Definition: CRNMath.h:47
Text AsText()
Converts to text.
Definition: CRNXml.cpp:158
Unintialized object error.
Definition: CRNException.h:155
~Histogram()
Destructor.
#define M_PI
Definition: CRNMath.h:38
#define CRNWarning(x)
Definition: CRNIO.h:145
unsigned int Max() const
Maximal count value.
void SetCeiling(unsigned int m)
Set maximal count value to m.
#define CRN_END_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:198
int GetTop() const
Returns the topmost coordinate.
Definition: CRNRect.h:107
size_t Argmax() const
First class having a maximal count value.
size_t Argmin() const
First class having a minimal count value.
int GetLeft() const
Returns the leftmost coordinate.
Definition: CRNRect.h:99
unsigned int GetBin(size_t k) const
Get a bin value.
ImageBW MakeRadialImageBW(size_t radius) const
returns the circular histogram image
A UTF32 character string class.
Definition: CRNString.h:61
A generic domain error.
Definition: CRNException.h:83
double Mean() const
Mean value on class indexes.
Histogram MakeIntersection(const Histogram &h) const
Intersection between two histograms.
void Append(const Histogram &h)
Appends an histogram to the current.
double EMD(const Histogram &h) const
Earth Mover's Distance.
XML text.
Definition: CRNXml.h:394
ImageBW MakeImageBW(size_t height) const
returns the histogram image
void SetBin(size_t k, unsigned int v)
Modify a bin value.
double Variance() const
Variance on class indexes.
#define CRN_DATA_FACTORY_REGISTER(elemname, classname)
Registers a class to the data factory.
size_t Size() const noexcept
Returns the number of bins.
Definition: CRNHistogram.h:157
constexpr TypeInfo< T >::SumType Twice(const T &v) noexcept(noexcept(v+v))
Returns the double of a value.
Definition: CRNMath.h:55
virtual StringUTF8 GetValue() const
Gets the content of the node.
Definition: CRNXml.cpp:171
void Cumulate()
Cumulates the values from 0 to end.
A dimension error.
Definition: CRNException.h:119
double Correlation(const Histogram &h) const
Correlation between two histograms.
void DrawLine(size_t x1, size_t y1, size_t x2, size_t y2, pixel_type color)
Draws a line using a specified color.
Definition: CRNImage.hpp:543
double Chi2(const Histogram &h) const
Correlation between two histograms.
Node GetFirstChild()
Gets the first child node.
Definition: CRNXml.cpp:303
size_t MedianValue() const
Computes the median value.
std::vector< size_t > Modes() const
Returns the modes.
int GetHeight() const
Returns the height of the rectangle.
Definition: CRNRect.h:119
void Abs(Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr) noexcept
Replaces each pixel by its absolute value.
Definition: CRNImageGray.h:47
std::vector< size_t > StableModes() const
Returns the stable modes.
size_t Fisher() const
Computes the Fisher threshold.
const T & Min(const T &a, const T &b)
Returns the min of two values.
Definition: CRNMath.h:49
double MinkowskiDistance(const Histogram &h, double r) const
Minkowski distance between two histograms.
Mother class for integer histograms.
Definition: CRNHistogram.h:44
Histogram()
Default constructor.
Definition: CRNHistogram.h:50
void AverageSmoothing(size_t d)
Smoothing histogram.
double CEMD(const Histogram &h) const
Circular Earth Mover's Distance.
int GetWidth() const
Returns the width of the rectangle.
Definition: CRNRect.h:115
Histogram MakePopulationHistogram() const
Creates an histogram from population.
size_t EntropyThreshold() const
Computes the entropy threshold.
String ToString() const
Dumps bins to a string.
A character string class.
Definition: CRNStringUTF8.h:49
unsigned int Min() const
Minimal count value.
unsigned int CumulateBins() const
Cumulate all bins.
crn::StringUTF8 ASCII85Encode(const uint8_t *const data, size_t len)
Encodes any data into a printable string.
Definition: CRNData.cpp:109
void ScaleMaxTo(unsigned int m)
Scale maximal count to m.
Element PushBackElement(const StringUTF8 &name)
Adds an element at the end of the children list.
Definition: CRNXml.cpp:355
XML node.
Definition: CRNXml.h:60
Invalid argument error (e.g.: nullptr pointer)
Definition: CRNException.h:107
double MatchDistance(const Histogram &h) const
Match distance between two histograms.
#define CRN_BEGIN_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:185
An item was not found in a container.
Definition: CRNException.h:95
void Resize(size_t newsize)
Resizes the histogram.
A rectangle class.
Definition: CRNRect.h:46