Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpHistogram.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Gray level histogram manipulation.
32 */
33
42
43#include <stdlib.h>
44#include <visp3/core/vpDisplay.h>
45#include <visp3/core/vpHistogram.h>
46#include <visp3/core/vpImageConvert.h>
47
49const unsigned int vpHistogram::constr_val_256 = 256;
50#if defined(VISP_HAVE_THREADS)
51#ifndef DOXYGEN_SHOULD_SKIP_THIS
52namespace
53{
54struct vpHistogram_Param_t
55{
56 unsigned int m_start_index;
57 unsigned int m_end_index;
58
59 unsigned int m_lut[256];
60 unsigned int *m_histogram;
61 const vpImage<unsigned char> *m_I;
62 const vpImage<bool> *m_mask;
63
64 vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr), m_mask(nullptr) { }
65
66 vpHistogram_Param_t(unsigned int start_index, unsigned int end_index, const vpImage<unsigned char> *const I, const vpImage<bool> *const mask)
67 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(nullptr), m_I(I), m_mask(mask)
68 { }
69
70 ~vpHistogram_Param_t()
71 {
72 if (m_histogram != nullptr) {
73 delete[] m_histogram;
74 }
75 }
76};
77
78void computeHistogramThread(vpHistogram_Param_t *histogram_param)
79{
80 unsigned int start_index = histogram_param->m_start_index;
81 unsigned int end_index = histogram_param->m_end_index;
82
83 const vpImage<unsigned char> *I = histogram_param->m_I;
84
85 unsigned char *ptrStart = (unsigned char *)(I->bitmap) + start_index;
86 unsigned char *ptrEnd = (unsigned char *)(I->bitmap) + end_index;
87 unsigned char *ptrCurrent = ptrStart;
88
89 const bool alwaysTrue = true;
90 const bool *ptrMaskCurrent = &alwaysTrue;
91 if (histogram_param->m_mask) {
92 ptrMaskCurrent = (const bool *)histogram_param->m_mask->bitmap + start_index;
93 }
94
95 if (end_index >= 8 + start_index) {
96 // Unroll loop version
97 for (; ptrCurrent <= ptrEnd - 8;) {
98 if (*ptrMaskCurrent) {
99 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
100 }
101 ++ptrCurrent;
102 if (histogram_param->m_mask != nullptr) {
103 ++ptrMaskCurrent;
104 }
105
106 if (*ptrMaskCurrent) {
107 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
108 }
109 ++ptrCurrent;
110 if (histogram_param->m_mask != nullptr) {
111 ++ptrMaskCurrent;
112 }
113
114 if (*ptrMaskCurrent) {
115 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
116 }
117 ++ptrCurrent;
118 if (histogram_param->m_mask != nullptr) {
119 ++ptrMaskCurrent;
120 }
121
122 if (*ptrMaskCurrent) {
123 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
124 }
125 ++ptrCurrent;
126 if (histogram_param->m_mask != nullptr) {
127 ++ptrMaskCurrent;
128 }
129
130 if (*ptrMaskCurrent) {
131 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
132 }
133 ++ptrCurrent;
134 if (histogram_param->m_mask != nullptr) {
135 ++ptrMaskCurrent;
136 }
137
138 if (*ptrMaskCurrent) {
139 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
140 }
141 ++ptrCurrent;
142 if (histogram_param->m_mask != nullptr) {
143 ++ptrMaskCurrent;
144 }
145
146 if (*ptrMaskCurrent) {
147 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
148 }
149 ++ptrCurrent;
150 if (histogram_param->m_mask != nullptr) {
151 ++ptrMaskCurrent;
152 }
153
154 if (*ptrMaskCurrent) {
155 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
156 }
157 ++ptrCurrent;
158 if (histogram_param->m_mask != nullptr) {
159 ++ptrMaskCurrent;
160 }
161 }
162 }
163
164 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
165 if (*ptrMaskCurrent) {
166 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
167 }
168 if (histogram_param->m_mask != nullptr) {
169 ++ptrMaskCurrent;
170 }
171 }
172}
173} // namespace
174#endif // DOXYGEN_SHOULD_SKIP_THIS
175#endif
176
177bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second);
178
179// comparison,
180bool compare_vpHistogramPeak(vpHistogramPeak first, vpHistogramPeak second)
181{
182 if (first.getValue() > second.getValue()) {
183 return true;
184 }
185 else {
186 return false;
187 }
188}
189
193vpHistogram::vpHistogram(const unsigned int &size) : m_histogram(nullptr), m_size(size), mp_mask(nullptr), m_total(0) { init(size); }
194
198vpHistogram::vpHistogram(const vpHistogram &h) : m_histogram(nullptr), m_size(constr_val_256), mp_mask(h.mp_mask), m_total(h.m_total)
199{
200 init(h.m_size);
201 memcpy(m_histogram, h.m_histogram, m_size * sizeof(unsigned));
202}
203
211vpHistogram::vpHistogram(const vpImage<unsigned char> &I) : m_histogram(nullptr), m_size(constr_val_256), mp_mask(nullptr), m_total(0)
212{
213 init();
214
215 calculate(I);
216}
217
226vpHistogram::vpHistogram(const vpImage<unsigned char> &I, const vpImage<bool> *p_mask) : m_histogram(nullptr), m_size(constr_val_256), mp_mask(nullptr), m_total(0)
227{
228 init();
229 setMask(p_mask);
230 calculate(I);
231}
232
237{
238 if (m_histogram != nullptr) {
239 delete[] m_histogram;
240 m_histogram = nullptr;
241 m_size = 0;
242 }
243}
244
259{
260 init(h.m_size);
261 memcpy(m_histogram, h.m_histogram, m_size * sizeof(unsigned));
262 mp_mask = h.mp_mask;
263 m_total = h.m_total;
264
265 return *this;
266}
267
273void vpHistogram::init(unsigned size_)
274{
275 if (m_histogram != nullptr) {
276 delete[] m_histogram;
277 m_histogram = nullptr;
278 }
279
280 this->m_size = size_;
281 m_histogram = new unsigned[m_size];
282
283 memset(m_histogram, 0, m_size * sizeof(unsigned));
284
285 mp_mask = nullptr;
286 m_total = 0;
287}
288
297void vpHistogram::calculate(const vpImage<unsigned char> &I, unsigned int nbins, unsigned int nbThreads)
298{
299 const unsigned int val_256 = 256;
300 if (m_size != nbins) {
301 if (m_histogram != nullptr) {
302 delete[] m_histogram;
303 m_histogram = nullptr;
304 }
305
306 m_size = nbins > val_256 ? val_256 : (nbins > 0 ? nbins : val_256);
307 if ((nbins > val_256) || (nbins == 0)) {
308 std::cerr << "nbins=" << nbins << " , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
309 }
310 m_histogram = new unsigned int[m_size];
311 }
312
313 memset(m_histogram, 0, m_size * sizeof(unsigned int));
314
315 bool use_single_thread;
316#if !defined(VISP_HAVE_THREADS)
317 use_single_thread = true;
318#else
319 use_single_thread = (nbThreads == 0 || nbThreads == 1);
320#endif
321
322 if ((!use_single_thread) && (I.getSize() <= nbThreads)) {
323 use_single_thread = true;
324 }
325
326 unsigned int lut[256];
327 for (unsigned int i = 0; i < val_256; ++i) {
328 lut[i] = static_cast<unsigned int>((i * m_size) / 256.0);
329 }
330
331 if (use_single_thread) {
332 // Single thread
333 const bool alwaysTrue = true;
334 const bool *ptrMaskCurrent = &alwaysTrue;
335 if (mp_mask) {
336 ptrMaskCurrent = static_cast<const bool *>(mp_mask->bitmap);
337 }
338
339 unsigned int size_ = I.getWidth() * I.getHeight();
340 unsigned char *ptrStart = static_cast<unsigned char *>(I.bitmap);
341 unsigned char *ptrEnd = ptrStart + size_;
342 unsigned char *ptrCurrent = ptrStart;
343
344 m_total = 0;
345 while (ptrCurrent != ptrEnd) {
346 if (*ptrMaskCurrent) {
347 ++m_histogram[lut[*ptrCurrent]];
348 ++m_total;
349 }
350 ++ptrCurrent;
351 if (mp_mask) {
352 ++ptrMaskCurrent;
353 }
354 }
355 }
356 else {
357#if defined(VISP_HAVE_THREADS)
358 // Multi-threads
359 std::vector<std::thread *> threadpool;
360 std::vector<vpHistogram_Param_t *> histogramParams;
361
362 unsigned int image_size = I.getSize();
363 unsigned int step = image_size / nbThreads;
364 unsigned int last_step = image_size - step * (nbThreads - 1);
365
366 for (unsigned int index = 0; index < nbThreads; ++index) {
367 unsigned int start_index = index * step;
368 unsigned int end_index = (index + 1) * step;
369
370 if (index == nbThreads - 1) {
371 end_index = start_index + last_step;
372 }
373
374 vpHistogram_Param_t *histogram_param = new vpHistogram_Param_t(start_index, end_index, &I, mp_mask);
375 histogram_param->m_histogram = new unsigned int[m_size];
376 histogram_param->m_mask = mp_mask;
377 memset(histogram_param->m_histogram, 0, m_size * sizeof(unsigned int));
378 memcpy(histogram_param->m_lut, lut, 256 * sizeof(unsigned int));
379
380 histogramParams.push_back(histogram_param);
381
382 // Start the threads
383 std::thread *histogram_thread = new std::thread(&computeHistogramThread, histogram_param);
384 threadpool.push_back(histogram_thread);
385 }
386
387 for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
388 // Wait until thread ends up
389 threadpool[cpt]->join();
390 }
391
392 m_total = 0;
393 for (unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
394 unsigned int sum = 0;
395
396 for (size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
397 sum += histogramParams[cpt2]->m_histogram[cpt1];
398 }
399
400 m_histogram[cpt1] = sum;
401 m_total += sum;
402 }
403
404 // Delete
405 for (size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
406 delete threadpool[cpt];
407 }
408
409 for (size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
410 delete histogramParams[cpt];
411 }
412#endif
413 }
414}
415
417{
418 // Compute the histogram
419 calculate(I);
420
421 // Calculate the cumulative distribution function
422 unsigned int cdf[256];
423 unsigned int cdfMin = std::numeric_limits<unsigned int>::max(), cdfMax = 0;
424 unsigned int minValue = std::numeric_limits<unsigned int>::max(), maxValue = 0;
425 cdf[0] = m_histogram[0];
426
427 if ((cdf[0] < cdfMin) && (cdf[0] > 0)) {
428 cdfMin = cdf[0];
429 minValue = 0;
430 }
431
432 const unsigned int val_256 = 256;
433 for (unsigned int i = 1; i < val_256; ++i) {
434 cdf[i] = cdf[i - 1] + m_histogram[i];
435
436 if ((cdf[i] < cdfMin) && (cdf[i] > 0)) {
437 cdfMin = cdf[i];
438 minValue = i;
439 }
440
441 if (cdf[i] > cdfMax) {
442 cdfMax = cdf[i];
443 maxValue = i;
444 }
445 }
446
447 unsigned int nbPixels = I.getWidth() * I.getHeight();
448 if (nbPixels == cdfMin) {
449 // Only one brightness value in the image
450 return;
451 }
452
453 // Construct the look-up table
454 unsigned char lut[256];
455 for (unsigned int x = minValue; x <= maxValue; ++x) {
456 lut[x] = vpMath::round(((cdf[x] - cdfMin) / static_cast<double>(nbPixels - cdfMin)) * 255.0);
457 }
458
459 Iout = I;
460 Iout.performLut(lut);
461}
462
474void vpHistogram::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness,
475 unsigned int maxValue_)
476{
477 unsigned int width = I.getWidth(), height = I.getHeight();
478 // Minimal width and height are 36 px
479 if ((width < 36) || (height < 36)) {
480 std::cerr << "Image I must have at least width >= 36 && height >= 36 !" << std::endl;
481 return;
482 }
483
484 unsigned int maxValue = maxValue_;
485 if (maxValue == 0) {
486 for (unsigned int i = 0; i < m_size; ++i) {
487 if (m_histogram[i] > maxValue) {
488 maxValue = m_histogram[i];
489 }
490 }
491 }
492
493 if (maxValue == 0) {
494 throw(vpException(vpException::divideByZeroError, "Cannot display histogram; max value=0"));
495 }
496 // Keep 12 free pixels at the top
497 unsigned int max_height = height - 12;
498 double ratio_height = max_height / static_cast<double>(maxValue);
499 double ratio_width = (width - 1) / static_cast<double>(m_size - 1.0);
500
501 for (unsigned int i = 1; i < m_size; ++i) {
502 unsigned int value1 = m_histogram[i - 1];
503 unsigned int value2 = m_histogram[i];
504
505 vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
506 vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
507 vpDisplay::displayLine(I, startPt, endPt, color, thickness);
508 }
509}
510
529void vpHistogram::smooth(unsigned int fsize)
530{
531 if (m_histogram == nullptr) {
532 throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
533 }
534
535 vpHistogram h;
536 h = *this;
537
538 unsigned int hsize = fsize / 2; // half filter size
539 unsigned int sizeAsInt = m_size;
540
541 for (unsigned int i = 0; i < sizeAsInt; ++i) {
542 unsigned int sum = 0;
543 unsigned int nb = 0;
544 for (unsigned int j = 0; j <= hsize; ++j) {
545 // exploitation of the overflow to detect negative value...
546 if ((i - j) < sizeAsInt) {
547 sum += h.m_histogram[i - j];
548 ++nb;
549 }
550 if ((i + j) < sizeAsInt) {
551 sum += h.m_histogram[i + j];
552 ++nb;
553 }
554 }
555 m_histogram[i] = sum / nb;
556 }
557}
558
573unsigned vpHistogram::getPeaks(std::list<vpHistogramPeak> &peaks)
574{
575 if (m_histogram == nullptr) {
576 throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
577 }
578
579 int prev_slope; // Previous histogram inclination
580 vpHistogramPeak p; // An histogram peak
581 unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
582
583 peaks.clear();
584
585 // Parse the histogram to get the local maxima
586 unsigned cpt = 0;
587 unsigned sum_level = 0;
588 nbpeaks = 0;
589 prev_slope = 1;
590
591 for (unsigned i = 0; i < (m_size - 1); ++i) {
592 int next_slope = static_cast<int>(m_histogram[i + 1]) - static_cast<int>(m_histogram[i]); // Next histogram inclination
593
594 if ((prev_slope > 0) && (next_slope == 0)) {
595 sum_level += i + 1;
596 ++cpt;
597 }
598 else {
599 // Peak detection
600 if ((prev_slope > 0) && (next_slope < 0)) {
601 sum_level += i;
602 ++cpt;
603
604 unsigned int level = sum_level / cpt;
605 p.set(static_cast<unsigned char>(level), m_histogram[level]);
606 peaks.push_back(p);
607
608 ++nbpeaks;
609 }
610
611 prev_slope = next_slope;
612 sum_level = 0;
613 cpt = 0;
614 }
615 }
616 if (prev_slope > 0) {
617 p.set(static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
618 peaks.push_back(p);
619 ++nbpeaks;
620 }
621
622 return nbpeaks;
623}
624
642unsigned vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peak1, vpHistogramPeak &peak2)
643{
644 std::list<vpHistogramPeak> peaks;
645 unsigned nbpeaks; // Number of peaks in the histogram (ie local maxima)
646 const unsigned int val_2 = 2;
647
648 nbpeaks = getPeaks(peaks);
649 sort(peaks);
650
651 if (nbpeaks == 0) {
652 peak1.set(0, 0);
653 peak2.set(0, 0);
654 return 0;
655 }
656
657 if (nbpeaks == 1) {
658 peak1 = peaks.front();
659 peak2.set(0, 0);
660 return 1;
661 }
662
663 // Parse the peaks list to get the peak with a distance greater
664 // than dist to the highest
665 peak1 = peaks.front();
666 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
667 for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks_end; ++it) {
668 vpHistogramPeak p = *it;
669 if (abs(p.getLevel() - peak1.getLevel()) > dist) {
670 // The second peak is found
671 peak2 = p;
672 return val_2;
673 }
674 }
675
676 // No second peak found
677 peak2.set(0, 0);
678 return 1;
679}
680
695
696bool vpHistogram::getPeaks(unsigned char dist, vpHistogramPeak &peakl, vpHistogramPeak &peakr, vpHistogramValey &valey)
697{
698 unsigned char *peak; // Local maxima values
699 int prev_slope; // Previous histogram inclination
700 unsigned index_highest_peak; // Index in peak[] array of the highest peak
701 unsigned index_second_peak; // Index in peak[] array of the second peak
702
703 unsigned int prof;
704 unsigned int maxprof; // Nb pixels difference between 2 maxi peaks
705 unsigned int nbmini; // Minimum numbers
706 unsigned int sumindmini; // Sum
707 unsigned int mini; // current minimum
708 unsigned int nbpeaks; // Number of peaks in the histogram (ie local maxima)
709
710 // Init the valey
711 valey.set(0, 0);
712
713 // Allocation for the
714 peak = new unsigned char[m_size];
715
716 // Parse the histogram to get the local maxima
717 nbpeaks = 0;
718 prev_slope = 1;
719 for (unsigned i = 0; i < (m_size - 1); ++i) {
720 int next_slope = static_cast<int>(m_histogram[i + 1]) - static_cast<int>(m_histogram[i]); // Next histogram inclination
721 if (next_slope == 0) {
722 // continue
723 }
724 else {
725 // Peak detection
726 if ((prev_slope > 0) && (next_slope < 0)) {
727 peak[nbpeaks++] = static_cast<unsigned char>(i);
728 }
729
730 prev_slope = next_slope;
731 }
732 }
733 if (prev_slope > 0) {
734 peak[nbpeaks++] = static_cast<unsigned char>(m_size - 1);
735 }
736
737 // Get the global maximum
738 index_highest_peak = 0;
739 for (unsigned int i = 0; i < nbpeaks; ++i) {
740 if (m_histogram[peak[i]] > m_histogram[peak[index_highest_peak]]) {
741 index_highest_peak = i;
742 }
743 }
744
745 maxprof = 0;
746 index_second_peak = index_highest_peak;
747
748 // Search second local maximum on the left of the global maximum
749 for (unsigned i = 0; i < index_highest_peak; ++i) {
750 if ((peak[index_highest_peak] - peak[i]) > dist) {
751 prof = 0;
752 for (int j = peak[i]; j <= (peak[index_highest_peak] - dist); ++j) {
753 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
754 prof = m_histogram[peak[i]] - m_histogram[j];
755 }
756 }
757
758 if (prof > maxprof) {
759 maxprof = prof;
760 index_second_peak = i;
761 }
762 }
763 }
764
765 // Search second local maximum on the right of the global maximum
766 for (unsigned i = index_highest_peak + 1; i < nbpeaks; ++i) {
767 if ((peak[i] - peak[index_highest_peak]) > dist) {
768 prof = 0;
769 for (int j = peak[index_highest_peak] + dist; j <= peak[i]; ++j) {
770 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
771 prof = m_histogram[peak[i]] - m_histogram[j];
772 }
773 }
774
775 if (prof > maxprof) {
776 maxprof = prof;
777 index_second_peak = i;
778 }
779 }
780 }
781
782 // Determine position of the first and second highest peaks
783 if (peak[index_highest_peak] < peak[index_second_peak]) {
784 peakr.set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
785 peakl.set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
786 }
787 else {
788 peakl.set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
789 peakr.set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
790 }
791
792 if (peakl == peakr) {
793
794 delete[] peak;
795
796 return false; // Not a bimodal histogram
797 }
798
799 // Search the valey
800 mini = peakl.getValue();
801 sumindmini = 0;
802 nbmini = 0;
803 unsigned peakr_level = peakr.getLevel();
804 for (unsigned i = peakl.getLevel(); i <= peakr_level; ++i) {
805 if (m_histogram[i] < mini) {
806 mini = m_histogram[i];
807 nbmini = 1;
808 sumindmini = i;
809 // continue
810 }
811 else {
812 if (m_histogram[i] == mini) {
813 sumindmini += i;
814 ++nbmini;
815 }
816 }
817 }
818
819 if (nbmini == 0) {
820 // no valey found
821 valey.set(0, 0);
822
823 delete[] peak;
824
825 return false;
826 }
827 else {
828 mini = sumindmini / nbmini; // mean
829 valey.set(static_cast<unsigned char>(mini), m_histogram[mini]);
830
831 delete[] peak;
832
833 return true;
834 }
835}
836
848unsigned vpHistogram::getValey(std::list<vpHistogramValey> &valey)
849{
850 if (m_histogram == nullptr) {
851 throw(vpImageException(vpImageException::notInitializedError, "Histogram array not initialised"));
852 }
853
854 int prev_slope; // Previous histogram inclination
855 vpHistogramValey p; // An histogram valey
856 unsigned nbvaley; // Number of valey in the histogram (ie local minima)
857
858 valey.clear();
859
860 // Parse the histogram to get the local minima
861 unsigned cpt = 0;
862 unsigned sum_level = 0;
863 nbvaley = 0;
864 prev_slope = -1;
865
866 for (unsigned i = 0; i < (m_size - 1); ++i) {
867 int next_slope = static_cast<int>(m_histogram[i + 1]) - static_cast<int>(m_histogram[i]); // Next histogram inclination
868
869 if ((prev_slope < 0) && (next_slope == 0)) {
870 sum_level += i + 1;
871 ++cpt;
872 // continue
873 }
874 else {
875 // Valey detection
876 if ((prev_slope < 0) && (next_slope > 0)) {
877 sum_level += i;
878 ++cpt;
879
880 unsigned int level = sum_level / cpt;
881 p.set(static_cast<unsigned char>(level), m_histogram[level]);
882 valey.push_back(p);
883
884 ++nbvaley;
885 }
886
887 prev_slope = next_slope;
888 sum_level = 0;
889 cpt = 0;
890 }
891 }
892 if (prev_slope < 0) {
893 p.set(static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
894 valey.push_back(p);
895 ++nbvaley;
896 }
897
898 return nbvaley;
899}
900
916{
917
918 // Set the left and right peaks
919 vpHistogramPeak peakl, peakr;
920 if (peak1.getLevel() > peak2.getLevel()) {
921 peakl = peak2;
922 peakr = peak1;
923 }
924 else {
925 peakl = peak1;
926 peakr = peak2;
927 }
928
929 // Search the valey
930 unsigned int nbmini; // Minimum numbers
931 unsigned int sumindmini; // Sum
932 unsigned int mini; // current minimum
933
934 mini = peakl.getValue();
935 sumindmini = 0;
936 nbmini = 0;
937 unsigned peakr_level = peakr.getLevel();
938 for (unsigned i = peakl.getLevel(); i <= peakr_level; ++i) {
939 if (m_histogram[i] < mini) {
940 mini = m_histogram[i];
941 nbmini = 1;
942 sumindmini = i;
943 // continue
944 }
945 else {
946 if (m_histogram[i] == mini) {
947 sumindmini += i;
948 ++nbmini;
949 }
950 }
951 }
952
953 if (nbmini == 0) {
954 // no valey found
955 valey.set(0, 0);
956
957 return false;
958 }
959 else {
960 unsigned int minipos = sumindmini / nbmini; // position of the minimum
961
962 valey.set(static_cast<unsigned char>(minipos), m_histogram[minipos]);
963 return true;
964 }
965}
966
984unsigned vpHistogram::getValey(unsigned char dist, const vpHistogramPeak &peak, vpHistogramValey &valeyl,
985 vpHistogramValey &valeyr)
986{
987 const unsigned int val_ui_0x10 = 0x10;
988 const unsigned int val_ui_0x11 = 0x11;
989 unsigned int ret = 0x11;
990 unsigned int nbmini; // Minimum numbers
991 unsigned int sumindmini; // Sum
992 unsigned int mini; // current minimum
993 vpHistogramPeak peakr, peakl; // Left and right peaks of peak
994 std::list<vpHistogramPeak> peaks; // list of histogram peaks
995 // unsigned int nbpeaks=0; // Number of peaks in the histogram (ie local
996 // maxima)
997
998 if (peak.getLevel() == 0) {
999 valeyl.set(0, 0);
1000 ret &= 0x01;
1001 }
1002 if (peak.getLevel() == (m_size - 1)) {
1003 valeyr.set(static_cast<unsigned char>(m_size - 1), 0);
1004 ret &= val_ui_0x10;
1005 }
1006
1007 if (ret >> 1) // consider the left part of the requested peak
1008 {
1009 // If the list of peaks is empty, compute it
1010 if (peaks.empty()) {
1011 /* nbpeaks = */ getPeaks(peaks);
1012 }
1013
1014 // Go to the requested peak in the list
1015 std::list<vpHistogramPeak>::const_iterator it;
1016 unsigned index = 0;
1017 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1018 for (it = peaks.begin(); it != peaks_end; ++it) {
1019 if (peak == *it) {
1020 // we are on the peak.
1021 break;
1022 }
1023 ++index;
1024 }
1025
1026 bool found = false;
1027 if (index == 0) {
1028 // No chance to get a peak on the left
1029 // should not occur !
1030 peakl.set(0, 0);
1031 }
1032 else {
1033 // search for the nearest peak on the left that matches the distance
1034 std::list<vpHistogramPeak>::const_iterator lit; // left iterator
1035 for (lit = peaks.begin(); lit != it; ++lit) {
1036 if (abs((*lit).getLevel() - peak.getLevel()) > dist) {
1037 // peakl found
1038 peakl = *lit;
1039 found = true; // we cannot stop here, since the other peaks on the
1040 // right may exist
1041 }
1042 }
1043 }
1044 if (!found) {
1045 peakl.set(0, 0);
1046 }
1047
1048 // Search the valey on the left
1049 mini = peak.getValue();
1050 sumindmini = 0;
1051 nbmini = 0;
1052 unsigned peak_level = peak.getLevel();
1053 for (unsigned i = peakl.getLevel(); i < peak_level; ++i) {
1054 if (m_histogram[i] < mini) {
1055 mini = m_histogram[i];
1056 nbmini = 1;
1057 sumindmini = i;
1058 // continue
1059 }
1060 else {
1061 if (m_histogram[i] == mini) {
1062 sumindmini += i;
1063 ++nbmini;
1064 }
1065 }
1066 }
1067 if (nbmini == 0) {
1068 valeyl.set(0, 0);
1069 ret &= 0x01;
1070 }
1071 else {
1072 unsigned int minipos = sumindmini / nbmini; // position of the minimum
1073 valeyl.set(static_cast<unsigned char>(minipos), m_histogram[minipos]);
1074 ret &= val_ui_0x11;
1075 }
1076 }
1077
1078 if (ret << 1) {
1079 // If the list of peaks is empty, compute it
1080 if (peaks.empty()) {
1081 /* nbpeaks = */ getPeaks(peaks);
1082 }
1083 // Go to the requested peak in the list
1084 std::list<vpHistogramPeak>::const_iterator it;
1085 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1086 for (it = peaks.begin(); it != peaks_end; ++it) {
1087 if (peak == *it) {
1088 // we are on the peak.
1089 break;
1090 }
1091 }
1092
1093 bool found = false;
1094 // search for the nearest peak on the right that matches the distance
1095 std::list<vpHistogramPeak>::const_iterator rit; // right iterator
1096 std::list<vpHistogramPeak>::const_iterator peaks_end_s = peaks.end();
1097 for (rit = it; rit != peaks_end_s; ++rit) {
1098
1099 if (abs((*rit).getLevel() - peak.getLevel()) > dist) {
1100 // peakr found
1101 peakr = *rit;
1102 found = true;
1103 break; // we can stop here
1104 }
1105 }
1106
1107 if (!found) {
1108 peakr.set(static_cast<unsigned char>(m_size - 1), 0);
1109 }
1110
1111 // Search the valey on the right
1112 mini = peak.getValue();
1113 sumindmini = 0;
1114 nbmini = 0;
1115 unsigned int peakr_level = static_cast<unsigned int>(peakr.getLevel());
1116 for (unsigned i = static_cast<unsigned int>(peak.getLevel()) + 1; i <= peakr_level; ++i) {
1117 if (m_histogram[i] < mini) {
1118 mini = m_histogram[i];
1119 nbmini = 1;
1120 sumindmini = i;
1121 // continue
1122 }
1123 else {
1124 if (m_histogram[i] == mini) {
1125 sumindmini += i;
1126 ++nbmini;
1127 }
1128 }
1129 }
1130 if (nbmini == 0) {
1131 valeyr.set(static_cast<unsigned char>(m_size - 1), 0);
1132 ret &= val_ui_0x10;
1133 }
1134 else {
1135 unsigned int minipos = sumindmini / nbmini; // position of the minimum
1136 valeyr.set(static_cast<unsigned char>(minipos), m_histogram[minipos]);
1137 ret &= val_ui_0x11;
1138 }
1139 }
1140
1141 return ret;
1142}
1143
1152unsigned vpHistogram::sort(std::list<vpHistogramPeak> &peaks)
1153{
1154
1155 if (peaks.empty()) {
1156 return 0;
1157 }
1158
1159 peaks.sort(compare_vpHistogramPeak);
1160
1161 return static_cast<unsigned int>(peaks.size());
1162}
1163
1175
1176bool vpHistogram::write(const std::string &filename) { return (this->write(filename.c_str())); }
1177
1189
1190bool vpHistogram::write(const char *filename)
1191{
1192 FILE *fd = fopen(filename, "w");
1193 if (fd == nullptr) {
1194 return false;
1195 }
1196 for (unsigned i = 0; i < m_size; ++i) {
1197 fprintf(fd, "%u %u\n", i, m_histogram[i]);
1198 }
1199 fclose(fd);
1200
1201 return true;
1202}
1203END_VISP_NAMESPACE
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
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:60
@ divideByZeroError
Division by zero.
Definition vpException.h:70
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)
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 setMask(const vpImage< bool > *p_mask)
Set a mask to ignore pixels for which the mask is false.
void equalize(const vpImage< unsigned char > &I, vpImage< unsigned char > &Iout)
vpHistogram(const unsigned int &size=256)
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 of the vpImage class member functions.
Definition vpImage.h:131
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
static int round(double x)
Definition vpMath.h:413