Visual Servoing Platform  version 3.5.1 under development (2023-03-14)
vpHistogram.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Author:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 
48 #include <stdlib.h>
49 #include <visp3/core/vpDisplay.h>
50 #include <visp3/core/vpHistogram.h>
51 #include <visp3/core/vpImageConvert.h>
52 
53 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
54 #include <visp3/core/vpThread.h>
55 
56 namespace
57 {
58 struct Histogram_Param_t {
59  unsigned int m_start_index;
60  unsigned int m_end_index;
61 
62  unsigned int m_lut[256];
63  unsigned int *m_histogram;
64  const vpImage<unsigned char> *m_I;
65 
66  Histogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(NULL), m_I(NULL) {}
67 
68  Histogram_Param_t(unsigned int start_index, unsigned int end_index, const vpImage<unsigned char> *const I)
69  : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(NULL), m_I(I)
70  {
71  }
72 
73  ~Histogram_Param_t()
74  {
75  if (m_histogram != NULL) {
76  delete[] m_histogram;
77  }
78  }
79 };
80 
81 vpThread::Return computeHistogramThread(vpThread::Args args)
82 {
83  Histogram_Param_t *histogram_param = static_cast<Histogram_Param_t *>(args);
84  unsigned int start_index = histogram_param->m_start_index;
85  unsigned int end_index = histogram_param->m_end_index;
86 
87  const vpImage<unsigned char> *I = histogram_param->m_I;
88 
89  unsigned char *ptrStart = (unsigned char *)(I->bitmap) + start_index;
90  unsigned char *ptrEnd = (unsigned char *)(I->bitmap) + end_index;
91  unsigned char *ptrCurrent = ptrStart;
92 
93  // while(ptrCurrent != ptrEnd) {
94  // histogram_param->m_histogram[ histogram_param->m_lut[ *ptrCurrent ]
95  // ] ++;
96  // ++ptrCurrent;
97  // }
98 
99  if (end_index - start_index >= 8) {
100  // Unroll loop version
101  for (; ptrCurrent <= ptrEnd - 8;) {
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  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
118  ++ptrCurrent;
119 
120  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
121  ++ptrCurrent;
122 
123  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
124  ++ptrCurrent;
125  }
126  }
127 
128  for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
129  histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
130  }
131 
132  return 0;
133 }
134 } // namespace
135 #endif
136 
137 bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second);
138 
139 // comparison,
140 bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second)
141 {
142  if (first.getValue() > second.getValue())
143  return true;
144  else
145  return false;
146 }
147 
151 vpHistogram::vpHistogram() : histogram(NULL), size(256) { init(); }
152 
156 vpHistogram::vpHistogram(const vpHistogram &h) : histogram(NULL), size(256)
157 {
158  init(h.size);
159  memcpy(histogram, h.histogram, size * sizeof(unsigned));
160 }
161 
169 vpHistogram::vpHistogram(const vpImage<unsigned char> &I) : histogram(NULL), size(256)
170 {
171  init();
172 
173  calculate(I);
174 }
175 
180 {
181  if (histogram != NULL) {
182  // vpTRACE("free: %p", &histogram);
183  delete[] histogram;
184  histogram = NULL;
185  size = 0;
186  }
187 }
188 
203 {
204  init(h.size);
205  memcpy(histogram, h.histogram, size * sizeof(unsigned));
206 
207  return *this;
208 }
209 
215 void vpHistogram::init(unsigned size_)
216 {
217  if (histogram != NULL) {
218  delete[] histogram;
219  histogram = NULL;
220  }
221 
222  this->size = size_;
223  histogram = new unsigned[size];
224 
225  memset(histogram, 0, size * sizeof(unsigned));
226 
227  // vpTRACE("alloc: %p", &histogram);
228 }
229 
238 void vpHistogram::calculate(const vpImage<unsigned char> &I, unsigned int nbins, unsigned int nbThreads)
239 {
240  if (size != nbins) {
241  if (histogram != NULL) {
242  delete[] histogram;
243  histogram = NULL;
244  }
245 
246  size = nbins > 256 ? 256 : (nbins > 0 ? nbins : 256);
247  if (nbins > 256 || nbins == 0) {
248  std::cerr << "nbins=" << nbins << " , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
249  }
250  histogram = new unsigned int[size];
251  }
252 
253  memset(histogram, 0, size * sizeof(unsigned int));
254 
255  bool use_single_thread;
256 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
257  use_single_thread = true;
258 #else
259  use_single_thread = (nbThreads == 0 || nbThreads == 1);
260 #endif
261 
262  if (!use_single_thread && I.getSize() <= nbThreads) {
263  use_single_thread = true;
264  }
265 
266  unsigned int lut[256];
267  for (unsigned int i = 0; i < 256; i++) {
268  lut[i] = (unsigned int)(i * size / 256.0);
269  }
270 
271  if (use_single_thread) {
272  // Single thread
273 
274  unsigned int size_ = I.getWidth() * I.getHeight();
275  unsigned char *ptrStart = (unsigned char *)I.bitmap;
276  unsigned char *ptrEnd = ptrStart + size_;
277  unsigned char *ptrCurrent = ptrStart;
278 
279  while (ptrCurrent != ptrEnd) {
280  histogram[lut[*ptrCurrent]]++;
281  ++ptrCurrent;
282  }
283  } else {
284 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
285  // Multi-threads
286 
287  std::vector<vpThread *> threadpool;
288  std::vector<Histogram_Param_t *> histogramParams;
289 
290  unsigned int image_size = I.getSize();
291  unsigned int step = image_size / nbThreads;
292  unsigned int last_step = image_size - step * (nbThreads - 1);
293 
294  for (unsigned int index = 0; index < nbThreads; index++) {
295  unsigned int start_index = index * step;
296  unsigned int end_index = (index + 1) * step;
297 
298  if (index == nbThreads - 1) {
299  end_index = start_index + last_step;
300  }
301 
302  Histogram_Param_t *histogram_param = new Histogram_Param_t(start_index, end_index, &I);
303  histogram_param->m_histogram = new unsigned int[size];
304  memset(histogram_param->m_histogram, 0, size * sizeof(unsigned int));
305  memcpy(histogram_param->m_lut, lut, 256 * sizeof(unsigned int));
306 
307  histogramParams.push_back(histogram_param);
308 
309  // Start the threads
310  vpThread *histogram_thread = new vpThread((vpThread::Fn)computeHistogramThread, (vpThread::Args)histogram_param);
311  threadpool.push_back(histogram_thread);
312  }
313 
314  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
315  // Wait until thread ends up
316  threadpool[cpt]->join();
317  }
318 
319  for (unsigned int cpt1 = 0; cpt1 < size; cpt1++) {
320  unsigned int sum = 0;
321 
322  for (size_t cpt2 = 0; cpt2 < histogramParams.size(); cpt2++) {
323  sum += histogramParams[cpt2]->m_histogram[cpt1];
324  }
325 
326  histogram[cpt1] = sum;
327  }
328 
329  // Delete
330  for (size_t cpt = 0; cpt < threadpool.size(); cpt++) {
331  delete threadpool[cpt];
332  }
333 
334  for (size_t cpt = 0; cpt < histogramParams.size(); cpt++) {
335  delete histogramParams[cpt];
336  }
337 #endif
338  }
339 }
340 
352 void vpHistogram::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness,
353  unsigned int maxValue_)
354 {
355  unsigned int width = I.getWidth(), height = I.getHeight();
356  // Minimal width and height are 36 px
357  if (width < 36 || height < 36) {
358  std::cerr << "Image I must have at least width >= 36 && height >= 36 !" << std::endl;
359  return;
360  }
361 
362  unsigned int maxValue = maxValue_;
363  if (maxValue == 0) {
364  for (unsigned int i = 0; i < size; i++) {
365  if (histogram[i] > maxValue) {
366  maxValue = histogram[i];
367  }
368  }
369  }
370 
371  if (maxValue == 0) {
372  throw(vpException(vpException::divideByZeroError, "Cannot display histogram; max value=0"));
373  }
374  // Keep 12 free pixels at the top
375  unsigned int max_height = height - 12;
376  double ratio_height = max_height / (double)maxValue;
377  double ratio_width = (width - 1) / (double)(size - 1.0);
378 
379  for (unsigned int i = 1; i < size; i++) {
380  unsigned int value1 = histogram[i - 1];
381  unsigned int value2 = histogram[i];
382 
383  vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
384  vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
385  vpDisplay::displayLine(I, startPt, endPt, color, thickness);
386  }
387 }
388 
407 void vpHistogram::smooth(unsigned int fsize)
408 {
409  if (histogram == NULL) {
410  vpERROR_TRACE("Histogram array not initialised\n");
411  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
412  }
413 
414  vpHistogram h;
415  h = *this;
416 
417  int hsize = (int)fsize / 2; // half filter size
418 
419  for (unsigned i = 0; i < size; i++) {
420  unsigned int sum = 0;
421  unsigned int nb = 0;
422  for (int j = -hsize; j <= hsize; j++) {
423  // exploitation of the overflow to detect negative value...
424  if (/*(i + j) >= 0 &&*/ (i + (unsigned int)j) < size) {
425  sum += h.histogram[i + (unsigned int)j];
426  nb++;
427  }
428  }
429  histogram[i] = sum / nb;
430  }
431 }
432 
447 unsigned vpHistogram::getPeaks(std::list<vpHistogramPeak> &peaks)
448 {
449  if (histogram == NULL) {
450  vpERROR_TRACE("Histogram array not initialised\n");
451  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
452  }
453 
454  int prev_slope; // Previous histogram inclination
455  vpHistogramPeak p; // An histogram peak
456  unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
457 
458  peaks.clear();
459 
460  // Parse the histogram to get the local maxima
461  unsigned cpt = 0;
462  unsigned sum_level = 0;
463  nbpeaks = 0;
464  prev_slope = 1;
465 
466  for (unsigned i = 0; i < size - 1; i++) {
467  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
468 
469  // if ((prev_slope < 0) && (next_slope > 0) ) {
470  // sum_level += i;
471  // cpt ++;
472  // continue;
473  // }
474 
475  if ((prev_slope > 0) && (next_slope == 0)) {
476  sum_level += i + 1;
477  cpt++;
478  continue;
479  }
480 
481  // Peak detection
482  if ((prev_slope > 0) && (next_slope < 0)) {
483  sum_level += i;
484  cpt++;
485 
486  unsigned int level = sum_level / cpt;
487  p.set((unsigned char)level, histogram[level]);
488  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
489  peaks.push_back(p);
490 
491  nbpeaks++;
492  }
493 
494  prev_slope = next_slope;
495  sum_level = 0;
496  cpt = 0;
497  }
498  if (prev_slope > 0) {
499  p.set((unsigned char)size - 1u, histogram[size - 1]);
500  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
501  peaks.push_back(p);
502  nbpeaks++;
503  }
504 
505  return nbpeaks;
506 }
507 
525 unsigned vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peak1, vpHistogramPeak &peak2)
526 {
527  std::list<vpHistogramPeak> peaks;
528  unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
529 
530  nbpeaks = getPeaks(peaks);
531  sort(peaks);
532 
533  if (nbpeaks == 0) {
534  peak1.set(0, 0);
535  peak2.set(0, 0);
536  return 0;
537  }
538 
539  if (nbpeaks == 1) {
540  peak1 = peaks.front();
541  peak2.set(0, 0);
542  return 1;
543  }
544 
545  // Parse the peaks list to get the peak with a distance greater
546  // than dist to the highest
547  peak1 = peaks.front();
548  for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it) {
549  vpHistogramPeak p = *it;
550  if (abs(p.getLevel() - peak1.getLevel()) > dist) {
551  // The second peak is found
552  peak2 = p;
553  return 2;
554  }
555  }
556 
557  // No second peak found
558  peak2.set(0, 0);
559  return 1;
560 }
561 
577 bool vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peakl, vpHistogramPeak &peakr, vpHistogramValey &valey)
578 {
579  unsigned char *peak; // Local maxima values
580  int prev_slope; // Previous histogram inclination
581  unsigned index_highest_peak; // Index in peak[] array of the highest peak
582  unsigned index_second_peak; // Index in peak[] array of the second peak
583 
584  unsigned int prof;
585  unsigned int maxprof; // Nb pixels difference between 2 maxi peaks
586  unsigned int nbmini; // Minimum numbers
587  unsigned int sumindmini; // Sum
588  unsigned int mini; // current minimum
589  unsigned int nbpeaks; // Number of peaks in the histogram (ie local maxima)
590 
591  // Init the valey
592  valey.set(0, 0);
593 
594  // Allocation for the
595  peak = new unsigned char[size];
596 
597  // Parse the histogram to get the local maxima
598  nbpeaks = 0;
599  prev_slope = 1;
600  for (unsigned i = 0; i < size - 1; i++) {
601  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
602  if (next_slope == 0)
603  continue;
604  // Peak detection
605  if ((prev_slope > 0) && (next_slope < 0))
606  peak[nbpeaks++] = (unsigned char)i;
607 
608  prev_slope = next_slope;
609  }
610  if (prev_slope > 0)
611  peak[nbpeaks++] = (unsigned char)(size - 1);
612 
613  // vpTRACE("nb peaks: %d", nbpeaks);
614  // for (unsigned i=0; i < nbpeaks; i ++)
615  // vpTRACE("peak %d: pos %d value: %d", i, peak[i], histogram[ peak[i]
616  // ]);
617 
618  // Get the global maximum
619  index_highest_peak = 0;
620  for (unsigned int i = 0; i < nbpeaks; i++) {
621  if (histogram[peak[i]] > histogram[peak[index_highest_peak]]) {
622  index_highest_peak = i;
623  }
624  }
625 
626  // vpTRACE("highest peak index: %d pos: %d value: %d",
627  // index_highest_peak, peak[index_highest_peak],
628  // histogram[ peak[index_highest_peak] ]);
629 
630  maxprof = 0;
631  index_second_peak = index_highest_peak;
632 
633  // Search second local maximum on the left of the global maximum
634  for (unsigned i = 0; i < index_highest_peak; i++) {
635  if (peak[index_highest_peak] - peak[i] > dist) {
636  prof = 0;
637  for (int j = peak[i]; j <= peak[index_highest_peak] - dist; j++)
638  if ((histogram[peak[i]] - histogram[j]) > prof)
639  prof = histogram[peak[i]] - histogram[j];
640 
641  if (prof > maxprof) {
642  maxprof = prof;
643  index_second_peak = i;
644  }
645  }
646  }
647 
648  // Search second local maximum on the right of the global maximum
649  for (unsigned i = index_highest_peak + 1; i < nbpeaks; i++) {
650  if (peak[i] - peak[index_highest_peak] > dist) {
651  prof = 0;
652  for (int j = peak[index_highest_peak] + dist; j <= peak[i]; j++)
653  if ((histogram[peak[i]] - histogram[j]) > prof)
654  prof = histogram[peak[i]] - histogram[j];
655 
656  if (prof > maxprof) {
657  maxprof = prof;
658  index_second_peak = i;
659  }
660  }
661  }
662  // vpTRACE("second peak index: %d pos: %d value: %d",
663  // index_second_peak, peak[index_second_peak],
664  // histogram[ peak[index_second_peak] ]);
665 
666  // Determine position of the first and second highest peaks
667  if (peak[index_highest_peak] < peak[index_second_peak]) {
668  peakr.set(peak[index_second_peak], histogram[peak[index_second_peak]]);
669  peakl.set(peak[index_highest_peak], histogram[peak[index_highest_peak]]);
670  } else {
671  peakl.set(peak[index_second_peak], histogram[peak[index_second_peak]]);
672  peakr.set(peak[index_highest_peak], histogram[peak[index_highest_peak]]);
673  }
674 
675  if (peakl == peakr) {
676 
677  delete[] peak;
678 
679  return (false); // Not a bimodal histogram
680  }
681 
682  // Search the valey
683  mini = peakl.getValue();
684  sumindmini = 0;
685  nbmini = 0;
686  for (unsigned i = peakl.getLevel(); i <= peakr.getLevel(); i++) {
687  if (histogram[i] < mini) {
688  mini = histogram[i];
689  nbmini = 1;
690  sumindmini = i;
691  continue;
692  }
693  if (histogram[i] == mini) {
694  sumindmini += i;
695  nbmini++;
696  }
697  }
698  // vpTRACE("nbmini %d", nbmini);
699  // vpTRACE("sumindmini %d", sumindmini);
700  // vpTRACE("mini: indmini: %d", sumindmini/nbmini);
701 
702  if (nbmini == 0) {
703  // no valey found
704  valey.set(0, 0);
705 
706  delete[] peak;
707 
708  return false;
709  } else {
710  mini = sumindmini / nbmini; // mean
711  valey.set((unsigned char)mini, histogram[mini]);
712 
713  delete[] peak;
714 
715  return (true);
716  }
717 }
718 
730 unsigned vpHistogram::getValey(std::list<vpHistogramValey> &valey)
731 {
732  if (histogram == NULL) {
733  vpERROR_TRACE("Histogram array not initialised\n");
734  throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
735  }
736 
737  int prev_slope; // Previous histogram inclination
738  vpHistogramValey p; // An histogram valey
739  unsigned nbvaley; // Number of valey in the histogram (ie local minima)
740 
741  valey.clear();
742 
743  // Parse the histogram to get the local minima
744  unsigned cpt = 0;
745  unsigned sum_level = 0;
746  nbvaley = 0;
747  prev_slope = -1;
748 
749  for (unsigned i = 0; i < size - 1; i++) {
750  int next_slope = (int)histogram[i + 1] - (int)histogram[i]; // Next histogram inclination
751 
752  if ((prev_slope < 0) && (next_slope == 0)) {
753  sum_level += i + 1;
754  cpt++;
755  continue;
756  }
757 
758  // Valey detection
759  if ((prev_slope < 0) && (next_slope > 0)) {
760  sum_level += i;
761  cpt++;
762 
763  unsigned int level = sum_level / cpt;
764  p.set((unsigned char)level, histogram[level]);
765  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
766  valey.push_back(p);
767 
768  nbvaley++;
769  }
770 
771  prev_slope = next_slope;
772  sum_level = 0;
773  cpt = 0;
774  }
775  if (prev_slope < 0) {
776  p.set((unsigned char)size - 1u, histogram[size - 1]);
777  // vpTRACE("add %d %d", p.getLevel(), p.getValue());
778  valey.push_back(p);
779  nbvaley++;
780  }
781 
782  return nbvaley;
783 }
784 
800 {
801 
802  // Set the left and right peaks
803  vpHistogramPeak peakl, peakr;
804  if (peak1.getLevel() > peak2.getLevel()) {
805  peakl = peak2;
806  peakr = peak1;
807  } else {
808  peakl = peak1;
809  peakr = peak2;
810  }
811 
812  // Search the valey
813  unsigned int nbmini; // Minimum numbers
814  unsigned int sumindmini; // Sum
815  unsigned int mini; // current minimum
816 
817  mini = peakl.getValue();
818  sumindmini = 0;
819  nbmini = 0;
820  for (unsigned i = peakl.getLevel(); i <= peakr.getLevel(); i++) {
821  if (histogram[i] < mini) {
822  mini = histogram[i];
823  nbmini = 1;
824  sumindmini = i;
825  continue;
826  }
827  if (histogram[i] == mini) {
828  sumindmini += i;
829  nbmini++;
830  }
831  }
832 
833  if (nbmini == 0) {
834  // no valey found
835  valey.set(0, 0);
836 
837  return false;
838  } else {
839  unsigned int minipos = sumindmini / nbmini; // position of the minimum
840 
841  valey.set((unsigned char)minipos, histogram[minipos]);
842  return true;
843  }
844 }
863 unsigned vpHistogram::getValey(unsigned char dist, const vpHistogramPeak &peak, vpHistogramValey &valeyl,
864  vpHistogramValey &valeyr)
865 {
866  unsigned int ret = 0x11;
867  unsigned int nbmini; // Minimum numbers
868  unsigned int sumindmini; // Sum
869  unsigned int mini; // current minimum
870  vpHistogramPeak peakr, peakl; // Left and right peaks of peak
871  std::list<vpHistogramPeak> peaks; // list of histogram peaks
872  // unsigned int nbpeaks=0; // Number of peaks in the histogram (ie local
873  // maxima)
874 
875  if (peak.getLevel() == 0) {
876  valeyl.set(0, 0);
877  ret &= 0x01;
878  }
879  if (peak.getLevel() == size - 1) {
880  valeyr.set((unsigned char)(size - 1), 0);
881  ret &= 0x10;
882  }
883 
884  if (ret >> 1) // consider the left part of the requested peak
885  {
886  // If the list of peaks is empty, compute it
887  if (peaks.empty()) {
888  /* nbpeaks = */ getPeaks(peaks);
889  }
890 
891  // if (1) {
892  // // vpTRACE("nb peaks: %d", nbpeaks);
893  // peaks.front();
894  // for (unsigned i=0; i < nbpeaks; i ++) {
895  // vpHistogramPeak p = peaks.value();
896  // // vpTRACE("peak index %d: pos %d value: %d",
897  // // i, p.getLevel(), p.getValue());
898  // peaks.next();
899  // }
900  // }
901  // Go to the requested peak in the list
902  std::list<vpHistogramPeak>::const_iterator it;
903  unsigned index = 0;
904  for (it = peaks.begin(); it != peaks.end(); ++it) {
905  if (peak == *it) {
906  // we are on the peak.
907  break;
908  }
909  index++;
910  }
911 
912  bool found = false;
913  if (index == 0) {
914  // No chance to get a peak on the left
915  // should not occur !
916  peakl.set(0, 0);
917  } else {
918  // search for the nearest peak on the left that matches the distance
919  std::list<vpHistogramPeak>::const_iterator lit; // left iterator
920  for (lit = peaks.begin(); lit != it; ++lit) {
921  if (abs((*lit).getLevel() - peak.getLevel()) > dist) {
922  // peakl found
923  peakl = *lit;
924  found = true; // we cannot stop here, since the other peaks on the
925  // right may exist
926  }
927  }
928  }
929  if (!found)
930  peakl.set(0, 0);
931 
932  // Search the valey on the left
933  mini = peak.getValue();
934  sumindmini = 0;
935  nbmini = 0;
936  for (unsigned i = peakl.getLevel(); i < peak.getLevel(); i++) {
937  if (histogram[i] < mini) {
938  mini = histogram[i];
939  nbmini = 1;
940  sumindmini = i;
941  continue;
942  }
943  if (histogram[i] == mini) {
944  sumindmini += i;
945  nbmini++;
946  }
947  }
948  if (nbmini == 0) {
949  valeyl.set(0, 0);
950  ret &= 0x01;
951  } else {
952  unsigned int minipos = sumindmini / nbmini; // position of the minimum
953  valeyl.set((unsigned char)minipos, histogram[minipos]);
954  ret &= 0x11;
955  }
956  }
957 
958  if (ret << 1) {
959  // If the list of peaks is empty, compute it
960  if (peaks.empty()) {
961  /* nbpeaks = */ getPeaks(peaks);
962  }
963  // Go to the requested peak in the list
964  std::list<vpHistogramPeak>::const_iterator it;
965  unsigned index = 0;
966  for (it = peaks.begin(); it != peaks.end(); ++it) {
967  if (peak == *it) {
968  // we are on the peak.
969  break;
970  }
971  index++;
972  }
973 
974  bool found = false;
975  // search for the nearest peak on the right that matches the distance
976  std::list<vpHistogramPeak>::const_iterator rit; // right iterator
977  for (rit = it; rit != peaks.end(); ++rit)
978 
979  if (abs((*rit).getLevel() - peak.getLevel()) > dist) {
980  // peakr found
981  peakr = *rit;
982  found = true;
983  break; // we can stop here
984  }
985 
986  if (!found)
987  peakr.set((unsigned char)(size - 1), 0);
988 
989  // Search the valey on the right
990  mini = peak.getValue();
991  sumindmini = 0;
992  nbmini = 0;
993  for (unsigned i = (unsigned int)peak.getLevel() + 1; i <= (unsigned int)peakr.getLevel(); i++) {
994  if (histogram[i] < mini) {
995  mini = histogram[i];
996  nbmini = 1;
997  sumindmini = i;
998  continue;
999  }
1000  if (histogram[i] == mini) {
1001  sumindmini += i;
1002  nbmini++;
1003  }
1004  }
1005  if (nbmini == 0) {
1006  valeyr.set((unsigned char)(size - 1), 0);
1007  ret &= 0x10;
1008  } else {
1009  unsigned int minipos = sumindmini / nbmini; // position of the minimum
1010  valeyr.set((unsigned char)minipos, histogram[minipos]);
1011  ret &= 0x11;
1012  }
1013  }
1014 
1015  return ret;
1016 }
1017 
1026 unsigned vpHistogram::sort(std::list<vpHistogramPeak> &peaks)
1027 {
1028 
1029  if (peaks.empty()) {
1030  return 0;
1031  }
1032 
1033  peaks.sort(compare_vpHistogramPeak);
1034 
1035  return (unsigned int)peaks.size();
1036 }
1037 
1050 bool vpHistogram::write(const std::string &filename) { return (this->write(filename.c_str())); }
1051 
1064 bool vpHistogram::write(const char *filename)
1065 {
1066  FILE *fd = fopen(filename, "w");
1067  if (fd == NULL)
1068  return false;
1069  for (unsigned i = 0; i < size; i++)
1070  fprintf(fd, "%u %u\n", i, histogram[i]);
1071  fclose(fd);
1072 
1073  return true;
1074 }
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:158
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 emited by ViSP classes.
Definition: vpException.h:72
@ divideByZeroError
Division by zero.
Definition: vpException.h:94
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:113
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)
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 emited by the vpImage class and its derivates.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:89
unsigned int getWidth() const
Definition: vpImage.h:247
unsigned int getSize() const
Definition: vpImage.h:228
Type * bitmap
points toward the bitmap
Definition: vpImage.h:144
unsigned int getHeight() const
Definition: vpImage.h:189
void *(* Fn)(Args)
Definition: vpThread.h:79
void * Return
Definition: vpThread.h:78
void * Args
Definition: vpThread.h:77
#define vpERROR_TRACE
Definition: vpDebug.h:393