Visual Servoing Platform  version 3.6.1 under development (2023-12-07)
vpHistogram.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Gray level histogram manipulation.
33  *
34 *****************************************************************************/
35 
45 #include <stdlib.h>
46 #include <visp3/core/vpDisplay.h>
47 #include <visp3/core/vpHistogram.h>
48 #include <visp3/core/vpImageConvert.h>
49 
50 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
51 #include <visp3/core/vpThread.h>
52 
53 namespace
54 {
55 struct vpHistogram_Param_t
56 {
57  unsigned int m_start_index;
58  unsigned int m_end_index;
59 
60  unsigned int m_lut[256];
61  unsigned int *m_histogram;
62  const vpImage<unsigned char> *m_I;
63 
64  vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr) { }
65 
66  vpHistogram_Param_t(unsigned int start_index, unsigned int end_index, const vpImage<unsigned char> *const I)
67  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(nullptr), m_I(I)
68  { }
69 
70  ~vpHistogram_Param_t()
71  {
72  if (m_histogram != nullptr) {
73  delete[] m_histogram;
74  }
75  }
76 };
77 
78 vpThread::Return computeHistogramThread(vpThread::Args args)
79 {
80  vpHistogram_Param_t *histogram_param = static_cast<vpHistogram_Param_t *>(args);
81  unsigned int start_index = histogram_param->m_start_index;
82  unsigned int end_index = histogram_param->m_end_index;
83 
84  const vpImage<unsigned char> *I = histogram_param->m_I;
85 
86  unsigned char *ptrStart = (unsigned char *)(I->bitmap) + start_index;
87  unsigned char *ptrEnd = (unsigned char *)(I->bitmap) + end_index;
88  unsigned char *ptrCurrent = ptrStart;
89 
90  if (end_index - start_index >= 8) {
91  // Unroll loop version
92  for (; ptrCurrent <= ptrEnd - 8;) {
93  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
94  ++ptrCurrent;
95 
96  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
97  ++ptrCurrent;
98 
99  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
100  ++ptrCurrent;
101 
102  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
103  ++ptrCurrent;
104 
105  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
106  ++ptrCurrent;
107 
108  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
109  ++ptrCurrent;
110 
111  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
112  ++ptrCurrent;
113 
114  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
115  ++ptrCurrent;
116  }
117  }
118 
119  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
120  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
121  }
122 
123  return 0;
124 }
125 } // namespace
126 #endif
127 
128 bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second);
129 
130 // comparison,
131 bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second)
132 {
133  if (first.getValue() > second.getValue())
134  return true;
135  else
136  return false;
137 }
138 
142 vpHistogram::vpHistogram() : histogram(nullptr), size(256) { init(); }
143 
147 vpHistogram::vpHistogram(const vpHistogram &h) : histogram(nullptr), size(256)
148 {
149  init(h.size);
150  memcpy(histogram, h.histogram, size * sizeof(unsigned));
151 }
152 
160 vpHistogram::vpHistogram(const vpImage<unsigned char> &I) : histogram(nullptr), size(256)
161 {
162  init();
163 
164  calculate(I);
165 }
166 
171 {
172  if (histogram != nullptr) {
173  // vpTRACE("free: %p", &histogram);
174  delete[] histogram;
175  histogram = nullptr;
176  size = 0;
177  }
178 }
179 
194 {
195  init(h.size);
196  memcpy(histogram, h.histogram, size * sizeof(unsigned));
197 
198  return *this;
199 }
200 
206 void vpHistogram::init(unsigned size_)
207 {
208  if (histogram != nullptr) {
209  delete[] histogram;
210  histogram = nullptr;
211  }
212 
213  this->size = size_;
214  histogram = new unsigned[size];
215 
216  memset(histogram, 0, size * sizeof(unsigned));
217 
218  // vpTRACE("alloc: %p", &histogram);
219 }
220 
229 void vpHistogram::calculate(const vpImage<unsigned char> &I, unsigned int nbins, unsigned int nbThreads)
230 {
231  if (size != nbins) {
232  if (histogram != nullptr) {
233  delete[] histogram;
234  histogram = nullptr;
235  }
236 
237  size = nbins > 256 ? 256 : (nbins > 0 ? nbins : 256);
238  if (nbins > 256 || nbins == 0) {
239  std::cerr << "nbins=" << nbins << " , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
240  }
241  histogram = new unsigned int[size];
242  }
243 
244  memset(histogram, 0, size * sizeof(unsigned int));
245 
246  bool use_single_thread;
247 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
248  use_single_thread = true;
249 #else
250  use_single_thread = (nbThreads == 0 || nbThreads == 1);
251 #endif
252 
253  if (!use_single_thread && I.getSize() <= nbThreads) {
254  use_single_thread = true;
255  }
256 
257  unsigned int lut[256];
258  for (unsigned int i = 0; i < 256; i++) {
259  lut[i] = (unsigned int)(i * size / 256.0);
260  }
261 
262  if (use_single_thread) {
263  // Single thread
264 
265  unsigned int size_ = I.getWidth() * I.getHeight();
266  unsigned char *ptrStart = (unsigned char *)I.bitmap;
267  unsigned char *ptrEnd = ptrStart + size_;
268  unsigned char *ptrCurrent = ptrStart;
269 
270  while (ptrCurrent != ptrEnd) {
271  histogram[lut[*ptrCurrent]]++;
272  ++ptrCurrent;
273  }
274  }
275  else {
276 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
277  // Multi-threads
278 
279  std::vector<vpThread *> threadpool;
280  std::vector<vpHistogram_Param_t *> histogramParams;
281 
282  unsigned int image_size = I.getSize();
283  unsigned int step = image_size / nbThreads;
284  unsigned int last_step = image_size - step * (nbThreads - 1);
285 
286  for (unsigned int index = 0; index < nbThreads; index++) {
287  unsigned int start_index = index * step;
288  unsigned int end_index = (index + 1) * step;
289 
290  if (index == nbThreads - 1) {
291  end_index = start_index + last_step;
292  }
293 
294  vpHistogram_Param_t *histogram_param = new vpHistogram_Param_t(start_index, end_index, &I);
295  histogram_param->m_histogram = new unsigned int[size];
296  memset(histogram_param->m_histogram, 0, size * sizeof(unsigned int));
297  memcpy(histogram_param->m_lut, lut, 256 * sizeof(unsigned int));
298 
299  histogramParams.push_back(histogram_param);
300 
301  // Start the threads
302  vpThread *histogram_thread = new vpThread((vpThread::Fn)computeHistogramThread, (vpThread::Args)histogram_param);
303  threadpool.push_back(histogram_thread);
304  }
305 
306  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
307  // Wait until thread ends up
308  threadpool[cpt]->join();
309  }
310 
311  for (unsigned int cpt1 = 0; cpt1 < size; cpt1++) {
312  unsigned int sum = 0;
313 
314  for (size_t cpt2 = 0; cpt2 < histogramParams.size(); cpt2++) {
315  sum += histogramParams[cpt2]->m_histogram[cpt1];
316  }
317 
318  histogram[cpt1] = sum;
319  }
320 
321  // Delete
322  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
323  delete threadpool[cpt];
324  }
325 
326  for (size_t cpt = 0; cpt < histogramParams.size(); cpt++) {
327  delete histogramParams[cpt];
328  }
329 #endif
330  }
331 }
332 
334 {
335  // Compute the histogram
336  calculate(I);
337 
338  // Calculate the cumulative distribution function
339  unsigned int cdf[256];
340  unsigned int cdfMin = std::numeric_limits<unsigned int>::max(), cdfMax = 0;
341  unsigned int minValue = std::numeric_limits<unsigned int>::max(), maxValue = 0;
342  cdf[0] = histogram[0];
343 
344  if (cdf[0] < cdfMin && cdf[0] > 0) {
345  cdfMin = cdf[0];
346  minValue = 0;
347  }
348 
349  for (unsigned int i = 1; i < 256; i++) {
350  cdf[i] = cdf[i - 1] + histogram[i];
351 
352  if (cdf[i] < cdfMin && cdf[i] > 0) {
353  cdfMin = cdf[i];
354  minValue = i;
355  }
356 
357  if (cdf[i] > cdfMax) {
358  cdfMax = cdf[i];
359  maxValue = i;
360  }
361  }
362 
363  unsigned int nbPixels = I.getWidth() * I.getHeight();
364  if (nbPixels == cdfMin) {
365  // Only one brightness value in the image
366  return;
367  }
368 
369  // Construct the look-up table
370  unsigned char lut[256];
371  for (unsigned int x = minValue; x <= maxValue; x++) {
372  lut[x] = vpMath::round((cdf[x] - cdfMin) / (double)(nbPixels - cdfMin) * 255.0);
373  }
374 
375  Iout = I;
376  Iout.performLut(lut);
377 }
378 
390 void vpHistogram::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness,
391  unsigned int maxValue_)
392 {
393  unsigned int width = I.getWidth(), height = I.getHeight();
394  // Minimal width and height are 36 px
395  if (width < 36 || height < 36) {
396  std::cerr << "Image I must have at least width >= 36 && height >= 36 !" << std::endl;
397  return;
398  }
399 
400  unsigned int maxValue = maxValue_;
401  if (maxValue == 0) {
402  for (unsigned int i = 0; i < size; i++) {
403  if (histogram[i] > maxValue) {
404  maxValue = histogram[i];
405  }
406  }
407  }
408 
409  if (maxValue == 0) {
410  throw(vpException(vpException::divideByZeroError, "Cannot display histogram; max value=0"));
411  }
412  // Keep 12 free pixels at the top
413  unsigned int max_height = height - 12;
414  double ratio_height = max_height / (double)maxValue;
415  double ratio_width = (width - 1) / (double)(size - 1.0);
416 
417  for (unsigned int i = 1; i < size; i++) {
418  unsigned int value1 = histogram[i - 1];
419  unsigned int value2 = histogram[i];
420 
421  vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
422  vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
423  vpDisplay::displayLine(I, startPt, endPt, color, thickness);
424  }
425 }
426 
445 void vpHistogram::smooth(unsigned int fsize)
446 {
447  if (histogram == nullptr) {
448  vpERROR_TRACE("Histogram array not initialised\n");
449  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
450  }
451 
452  vpHistogram h;
453  h = *this;
454 
455  int hsize = (int)fsize / 2; // half filter size
456 
457  for (unsigned i = 0; i < size; i++) {
458  unsigned int sum = 0;
459  unsigned int nb = 0;
460  for (int j = -hsize; j <= hsize; j++) {
461  // exploitation of the overflow to detect negative value...
462  if (/*(i + j) >= 0 &&*/ (i + (unsigned int)j) < size) {
463  sum += h.histogram[i + (unsigned int)j];
464  nb++;
465  }
466  }
467  histogram[i] = sum / nb;
468  }
469 }
470 
485 unsigned vpHistogram::getPeaks(std::list<vpHistogramPeak> &peaks)
486 {
487  if (histogram == nullptr) {
488  vpERROR_TRACE("Histogram array not initialised\n");
489  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
490  }
491 
492  int prev_slope; // Previous histogram inclination
493  vpHistogramPeak p; // An histogram peak
494  unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
495 
496  peaks.clear();
497 
498  // Parse the histogram to get the local maxima
499  unsigned cpt = 0;
500  unsigned sum_level = 0;
501  nbpeaks = 0;
502  prev_slope = 1;
503 
504  for (unsigned i = 0; i < size - 1; i++) {
505  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
506 
507  // if ((prev_slope < 0) && (next_slope > 0) ) {
508  // sum_level += i;
509  // cpt ++;
510  // continue;
511  // }
512 
513  if ((prev_slope > 0) && (next_slope == 0)) {
514  sum_level += i + 1;
515  cpt++;
516  continue;
517  }
518 
519  // Peak detection
520  if ((prev_slope > 0) && (next_slope < 0)) {
521  sum_level += i;
522  cpt++;
523 
524  unsigned int level = sum_level / cpt;
525  p.set((unsigned char)level, histogram[level]);
526  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
527  peaks.push_back(p);
528 
529  nbpeaks++;
530  }
531 
532  prev_slope = next_slope;
533  sum_level = 0;
534  cpt = 0;
535  }
536  if (prev_slope > 0) {
537  p.set((unsigned char)size - 1u, histogram[size - 1]);
538  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
539  peaks.push_back(p);
540  nbpeaks++;
541  }
542 
543  return nbpeaks;
544 }
545 
563 unsigned vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peak1, vpHistogramPeak &peak2)
564 {
565  std::list<vpHistogramPeak> peaks;
566  unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
567 
568  nbpeaks = getPeaks(peaks);
569  sort(peaks);
570 
571  if (nbpeaks == 0) {
572  peak1.set(0, 0);
573  peak2.set(0, 0);
574  return 0;
575  }
576 
577  if (nbpeaks == 1) {
578  peak1 = peaks.front();
579  peak2.set(0, 0);
580  return 1;
581  }
582 
583  // Parse the peaks list to get the peak with a distance greater
584  // than dist to the highest
585  peak1 = peaks.front();
586  for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it) {
587  vpHistogramPeak p = *it;
588  if (abs(p.getLevel() - peak1.getLevel()) > dist) {
589  // The second peak is found
590  peak2 = p;
591  return 2;
592  }
593  }
594 
595  // No second peak found
596  peak2.set(0, 0);
597  return 1;
598 }
599 
615 bool vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peakl, vpHistogramPeak &peakr, vpHistogramValey &valey)
616 {
617  unsigned char *peak; // Local maxima values
618  int prev_slope; // Previous histogram inclination
619  unsigned index_highest_peak; // Index in peak[] array of the highest peak
620  unsigned index_second_peak; // Index in peak[] array of the second peak
621 
622  unsigned int prof;
623  unsigned int maxprof; // Nb pixels difference between 2 maxi peaks
624  unsigned int nbmini; // Minimum numbers
625  unsigned int sumindmini; // Sum
626  unsigned int mini; // current minimum
627  unsigned int nbpeaks; // Number of peaks in the histogram (ie local maxima)
628 
629  // Init the valey
630  valey.set(0, 0);
631 
632  // Allocation for the
633  peak = new unsigned char[size];
634 
635  // Parse the histogram to get the local maxima
636  nbpeaks = 0;
637  prev_slope = 1;
638  for (unsigned i = 0; i < size - 1; i++) {
639  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
640  if (next_slope == 0)
641  continue;
642  // Peak detection
643  if ((prev_slope > 0) && (next_slope < 0))
644  peak[nbpeaks++] = (unsigned char)i;
645 
646  prev_slope = next_slope;
647  }
648  if (prev_slope > 0)
649  peak[nbpeaks++] = (unsigned char)(size - 1);
650 
651  // Get the global maximum
652  index_highest_peak = 0;
653  for (unsigned int i = 0; i < nbpeaks; i++) {
654  if (histogram[peak[i]] > histogram[peak[index_highest_peak]]) {
655  index_highest_peak = i;
656  }
657  }
658 
659  maxprof = 0;
660  index_second_peak = index_highest_peak;
661 
662  // Search second local maximum on the left of the global maximum
663  for (unsigned i = 0; i < index_highest_peak; i++) {
664  if (peak[index_highest_peak] - peak[i] > dist) {
665  prof = 0;
666  for (int j = peak[i]; j <= peak[index_highest_peak] - dist; j++)
667  if ((histogram[peak[i]] - histogram[j]) > prof)
668  prof = histogram[peak[i]] - histogram[j];
669 
670  if (prof > maxprof) {
671  maxprof = prof;
672  index_second_peak = i;
673  }
674  }
675  }
676 
677  // Search second local maximum on the right of the global maximum
678  for (unsigned i = index_highest_peak + 1; i < nbpeaks; i++) {
679  if (peak[i] - peak[index_highest_peak] > dist) {
680  prof = 0;
681  for (int j = peak[index_highest_peak] + dist; j <= peak[i]; j++)
682  if ((histogram[peak[i]] - histogram[j]) > prof)
683  prof = histogram[peak[i]] - histogram[j];
684 
685  if (prof > maxprof) {
686  maxprof = prof;
687  index_second_peak = i;
688  }
689  }
690  }
691 
692  // Determine position of the first and second highest peaks
693  if (peak[index_highest_peak] < peak[index_second_peak]) {
694  peakr.set(peak[index_second_peak], histogram[peak[index_second_peak]]);
695  peakl.set(peak[index_highest_peak], histogram[peak[index_highest_peak]]);
696  }
697  else {
698  peakl.set(peak[index_second_peak], histogram[peak[index_second_peak]]);
699  peakr.set(peak[index_highest_peak], histogram[peak[index_highest_peak]]);
700  }
701 
702  if (peakl == peakr) {
703 
704  delete[] peak;
705 
706  return (false); // Not a bimodal histogram
707  }
708 
709  // Search the valey
710  mini = peakl.getValue();
711  sumindmini = 0;
712  nbmini = 0;
713  for (unsigned i = peakl.getLevel(); i <= peakr.getLevel(); i++) {
714  if (histogram[i] < mini) {
715  mini = histogram[i];
716  nbmini = 1;
717  sumindmini = i;
718  continue;
719  }
720  if (histogram[i] == mini) {
721  sumindmini += i;
722  nbmini++;
723  }
724  }
725  // vpTRACE("nbmini %d", nbmini);
726  // vpTRACE("sumindmini %d", sumindmini);
727  // vpTRACE("mini: indmini: %d", sumindmini/nbmini);
728 
729  if (nbmini == 0) {
730  // no valey found
731  valey.set(0, 0);
732 
733  delete[] peak;
734 
735  return false;
736  }
737  else {
738  mini = sumindmini / nbmini; // mean
739  valey.set((unsigned char)mini, histogram[mini]);
740 
741  delete[] peak;
742 
743  return (true);
744  }
745 }
746 
758 unsigned vpHistogram::getValey(std::list<vpHistogramValey> &valey)
759 {
760  if (histogram == nullptr) {
761  vpERROR_TRACE("Histogram array not initialised\n");
762  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
763  }
764 
765  int prev_slope; // Previous histogram inclination
766  vpHistogramValey p; // An histogram valey
767  unsigned nbvaley; // Number of valey in the histogram (ie local minima)
768 
769  valey.clear();
770 
771  // Parse the histogram to get the local minima
772  unsigned cpt = 0;
773  unsigned sum_level = 0;
774  nbvaley = 0;
775  prev_slope = -1;
776 
777  for (unsigned i = 0; i < size - 1; i++) {
778  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
779 
780  if ((prev_slope < 0) && (next_slope == 0)) {
781  sum_level += i + 1;
782  cpt++;
783  continue;
784  }
785 
786  // Valey detection
787  if ((prev_slope < 0) && (next_slope > 0)) {
788  sum_level += i;
789  cpt++;
790 
791  unsigned int level = sum_level / cpt;
792  p.set((unsigned char)level, histogram[level]);
793  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
794  valey.push_back(p);
795 
796  nbvaley++;
797  }
798 
799  prev_slope = next_slope;
800  sum_level = 0;
801  cpt = 0;
802  }
803  if (prev_slope < 0) {
804  p.set((unsigned char)size - 1u, histogram[size - 1]);
805  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
806  valey.push_back(p);
807  nbvaley++;
808  }
809 
810  return nbvaley;
811 }
812 
828 {
829 
830  // Set the left and right peaks
831  vpHistogramPeak peakl, peakr;
832  if (peak1.getLevel() > peak2.getLevel()) {
833  peakl = peak2;
834  peakr = peak1;
835  }
836  else {
837  peakl = peak1;
838  peakr = peak2;
839  }
840 
841  // Search the valey
842  unsigned int nbmini; // Minimum numbers
843  unsigned int sumindmini; // Sum
844  unsigned int mini; // current minimum
845 
846  mini = peakl.getValue();
847  sumindmini = 0;
848  nbmini = 0;
849  for (unsigned i = peakl.getLevel(); i <= peakr.getLevel(); i++) {
850  if (histogram[i] < mini) {
851  mini = histogram[i];
852  nbmini = 1;
853  sumindmini = i;
854  continue;
855  }
856  if (histogram[i] == mini) {
857  sumindmini += i;
858  nbmini++;
859  }
860  }
861 
862  if (nbmini == 0) {
863  // no valey found
864  valey.set(0, 0);
865 
866  return false;
867  }
868  else {
869  unsigned int minipos = sumindmini / nbmini; // position of the minimum
870 
871  valey.set((unsigned char)minipos, histogram[minipos]);
872  return true;
873  }
874 }
893 unsigned vpHistogram::getValey(unsigned char dist, const vpHistogramPeak &peak, vpHistogramValey &valeyl,
894  vpHistogramValey &valeyr)
895 {
896  unsigned int ret = 0x11;
897  unsigned int nbmini; // Minimum numbers
898  unsigned int sumindmini; // Sum
899  unsigned int mini; // current minimum
900  vpHistogramPeak peakr, peakl; // Left and right peaks of peak
901  std::list<vpHistogramPeak> peaks; // list of histogram peaks
902  // unsigned int nbpeaks=0; // Number of peaks in the histogram (ie local
903  // maxima)
904 
905  if (peak.getLevel() == 0) {
906  valeyl.set(0, 0);
907  ret &= 0x01;
908  }
909  if (peak.getLevel() == size - 1) {
910  valeyr.set((unsigned char)(size - 1), 0);
911  ret &= 0x10;
912  }
913 
914  if (ret >> 1) // consider the left part of the requested peak
915  {
916  // If the list of peaks is empty, compute it
917  if (peaks.empty()) {
918  /* nbpeaks = */ getPeaks(peaks);
919  }
920 
921  // Go to the requested peak in the list
922  std::list<vpHistogramPeak>::const_iterator it;
923  unsigned index = 0;
924  for (it = peaks.begin(); it != peaks.end(); ++it) {
925  if (peak == *it) {
926  // we are on the peak.
927  break;
928  }
929  index++;
930  }
931 
932  bool found = false;
933  if (index == 0) {
934  // No chance to get a peak on the left
935  // should not occur !
936  peakl.set(0, 0);
937  }
938  else {
939  // search for the nearest peak on the left that matches the distance
940  std::list<vpHistogramPeak>::const_iterator lit; // left iterator
941  for (lit = peaks.begin(); lit != it; ++lit) {
942  if (abs((*lit).getLevel() - peak.getLevel()) > dist) {
943  // peakl found
944  peakl = *lit;
945  found = true; // we cannot stop here, since the other peaks on the
946  // right may exist
947  }
948  }
949  }
950  if (!found)
951  peakl.set(0, 0);
952 
953  // Search the valey on the left
954  mini = peak.getValue();
955  sumindmini = 0;
956  nbmini = 0;
957  for (unsigned i = peakl.getLevel(); i < peak.getLevel(); i++) {
958  if (histogram[i] < mini) {
959  mini = histogram[i];
960  nbmini = 1;
961  sumindmini = i;
962  continue;
963  }
964  if (histogram[i] == mini) {
965  sumindmini += i;
966  nbmini++;
967  }
968  }
969  if (nbmini == 0) {
970  valeyl.set(0, 0);
971  ret &= 0x01;
972  }
973  else {
974  unsigned int minipos = sumindmini / nbmini; // position of the minimum
975  valeyl.set((unsigned char)minipos, histogram[minipos]);
976  ret &= 0x11;
977  }
978  }
979 
980  if (ret << 1) {
981  // If the list of peaks is empty, compute it
982  if (peaks.empty()) {
983  /* nbpeaks = */ getPeaks(peaks);
984  }
985  // Go to the requested peak in the list
986  std::list<vpHistogramPeak>::const_iterator it;
987  for (it = peaks.begin(); it != peaks.end(); ++it) {
988  if (peak == *it) {
989  // we are on the peak.
990  break;
991  }
992  }
993 
994  bool found = false;
995  // search for the nearest peak on the right that matches the distance
996  std::list<vpHistogramPeak>::const_iterator rit; // right iterator
997  for (rit = it; rit != peaks.end(); ++rit)
998 
999  if (abs((*rit).getLevel() - peak.getLevel()) > dist) {
1000  // peakr found
1001  peakr = *rit;
1002  found = true;
1003  break; // we can stop here
1004  }
1005 
1006  if (!found)
1007  peakr.set((unsigned char)(size - 1), 0);
1008 
1009  // Search the valey on the right
1010  mini = peak.getValue();
1011  sumindmini = 0;
1012  nbmini = 0;
1013  for (unsigned i = (unsigned int)peak.getLevel() + 1; i <= (unsigned int)peakr.getLevel(); i++) {
1014  if (histogram[i] < mini) {
1015  mini = histogram[i];
1016  nbmini = 1;
1017  sumindmini = i;
1018  continue;
1019  }
1020  if (histogram[i] == mini) {
1021  sumindmini += i;
1022  nbmini++;
1023  }
1024  }
1025  if (nbmini == 0) {
1026  valeyr.set((unsigned char)(size - 1), 0);
1027  ret &= 0x10;
1028  }
1029  else {
1030  unsigned int minipos = sumindmini / nbmini; // position of the minimum
1031  valeyr.set((unsigned char)minipos, histogram[minipos]);
1032  ret &= 0x11;
1033  }
1034  }
1035 
1036  return ret;
1037 }
1038 
1047 unsigned vpHistogram::sort(std::list<vpHistogramPeak> &peaks)
1048 {
1049 
1050  if (peaks.empty()) {
1051  return 0;
1052  }
1053 
1054  peaks.sort(compare_vpHistogramPeak);
1055 
1056  return (unsigned int)peaks.size();
1057 }
1058 
1071 bool vpHistogram::write(const std::string &filename) { return (this->write(filename.c_str())); }
1072 
1085 bool vpHistogram::write(const char *filename)
1086 {
1087  FILE *fd = fopen(filename, "w");
1088  if (fd == nullptr)
1089  return false;
1090  for (unsigned i = 0; i < size; i++)
1091  fprintf(fd, "%u %u\n", i, histogram[i]);
1092  fclose(fd);
1093 
1094  return true;
1095 }
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ divideByZeroError
Division by zero.
Definition: vpException.h:82
Declaration of the peak (maximum value) in a gray level image histogram.
void set(unsigned char lvl, unsigned val)
unsigned getValue() const
unsigned char getLevel() const
Declaration of the valey (minimum value) in a gray level image histogram.
void set(unsigned char lvl, unsigned val)
Class to compute a gray level image histogram.
Definition: vpHistogram.h:108
unsigned getPeaks(std::list< vpHistogramPeak > &peaks)
void smooth(unsigned int fsize=3)
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
vpHistogram & operator=(const vpHistogram &h)
unsigned sort(std::list< vpHistogramPeak > &peaks)
virtual ~vpHistogram()
unsigned getValey(std::list< vpHistogramValey > &valey)
void equalize(const vpImage< unsigned char > &I, vpImage< unsigned char > &Iout)
bool write(const std::string &filename)
void display(const vpImage< unsigned char > &I, const vpColor &color=vpColor::white, unsigned int thickness=2, unsigned int maxValue_=0)
Error that can be emitted by the vpImage class and its derivatives.
@ notInitializedError
Image not initialized.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
unsigned int getWidth() const
Definition: vpImage.h:240
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:2013
unsigned int getSize() const
Definition: vpImage.h:221
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:182
static int round(double x)
Definition: vpMath.h:403
void *(* Fn)(Args)
Definition: vpThread.h:74
void * Return
Definition: vpThread.h:73
void * Args
Definition: vpThread.h:72
#define vpERROR_TRACE
Definition: vpDebug.h:388