45 #include <visp3/core/vpDisplay.h>
46 #include <visp3/core/vpHistogram.h>
47 #include <visp3/core/vpImageConvert.h>
50 const unsigned int vpHistogram::constr_val_256 = 256;
51 #if defined(VISP_HAVE_THREADS)
54 #ifndef DOXYGEN_SHOULD_SKIP_THIS
57 struct vpHistogram_Param_t
59 unsigned int m_start_index;
60 unsigned int m_end_index;
62 unsigned int m_lut[256];
63 unsigned int *m_histogram;
67 vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr), m_mask(nullptr) { }
70 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(nullptr), m_I(I), m_mask(mask)
73 ~vpHistogram_Param_t()
75 if (m_histogram !=
nullptr) {
81 void computeHistogramThread(vpHistogram_Param_t *histogram_param)
83 unsigned int start_index = histogram_param->m_start_index;
84 unsigned int end_index = histogram_param->m_end_index;
88 unsigned char *ptrStart = (
unsigned char *)(I->
bitmap) + start_index;
89 unsigned char *ptrEnd = (
unsigned char *)(I->
bitmap) + end_index;
90 unsigned char *ptrCurrent = ptrStart;
92 const bool alwaysTrue =
true;
93 const bool *ptrMaskCurrent = &alwaysTrue;
94 if (histogram_param->m_mask) {
95 ptrMaskCurrent = (
const bool *)histogram_param->m_mask->bitmap + start_index;
98 if (end_index >= 8 + start_index) {
100 for (; ptrCurrent <= ptrEnd - 8;) {
101 if (*ptrMaskCurrent) {
102 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
105 if (histogram_param->m_mask !=
nullptr) {
109 if (*ptrMaskCurrent) {
110 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
113 if (histogram_param->m_mask !=
nullptr) {
117 if (*ptrMaskCurrent) {
118 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
121 if (histogram_param->m_mask !=
nullptr) {
125 if (*ptrMaskCurrent) {
126 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
129 if (histogram_param->m_mask !=
nullptr) {
133 if (*ptrMaskCurrent) {
134 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
137 if (histogram_param->m_mask !=
nullptr) {
141 if (*ptrMaskCurrent) {
142 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
145 if (histogram_param->m_mask !=
nullptr) {
149 if (*ptrMaskCurrent) {
150 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
153 if (histogram_param->m_mask !=
nullptr) {
157 if (*ptrMaskCurrent) {
158 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
161 if (histogram_param->m_mask !=
nullptr) {
167 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
168 if (*ptrMaskCurrent) {
169 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
171 if (histogram_param->m_mask !=
nullptr) {
204 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
241 if (m_histogram !=
nullptr) {
242 delete[] m_histogram;
243 m_histogram =
nullptr;
264 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
276 void vpHistogram::init(
unsigned size_)
278 if (m_histogram !=
nullptr) {
279 delete[] m_histogram;
280 m_histogram =
nullptr;
283 this->m_size = size_;
284 m_histogram =
new unsigned[m_size];
286 memset(m_histogram, 0, m_size *
sizeof(
unsigned));
302 const unsigned int val_256 = 256;
303 if (m_size != nbins) {
304 if (m_histogram !=
nullptr) {
305 delete[] m_histogram;
306 m_histogram =
nullptr;
309 m_size = nbins > val_256 ? val_256 : (nbins > 0 ? nbins : val_256);
310 if ((nbins > val_256) || (nbins == 0)) {
311 std::cerr <<
"nbins=" << nbins <<
" , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
313 m_histogram =
new unsigned int[m_size];
316 memset(m_histogram, 0, m_size *
sizeof(
unsigned int));
318 bool use_single_thread;
319 #if !defined(VISP_HAVE_THREADS)
320 use_single_thread =
true;
322 use_single_thread = (nbThreads == 0 || nbThreads == 1);
325 if ((!use_single_thread) && (I.
getSize() <= nbThreads)) {
326 use_single_thread =
true;
329 unsigned int lut[256];
330 for (
unsigned int i = 0; i < val_256; ++i) {
331 lut[i] =
static_cast<unsigned int>((i * m_size) / 256.0);
334 if (use_single_thread) {
336 const bool alwaysTrue =
true;
337 const bool *ptrMaskCurrent = &alwaysTrue;
339 ptrMaskCurrent =
static_cast<const bool *
>(mp_mask->
bitmap);
343 unsigned char *ptrStart =
static_cast<unsigned char *
>(I.
bitmap);
344 unsigned char *ptrEnd = ptrStart + size_;
345 unsigned char *ptrCurrent = ptrStart;
348 while (ptrCurrent != ptrEnd) {
349 if (*ptrMaskCurrent) {
350 ++m_histogram[lut[*ptrCurrent]];
360 #if defined(VISP_HAVE_THREADS)
362 std::vector<std::thread *> threadpool;
363 std::vector<vpHistogram_Param_t *> histogramParams;
365 unsigned int image_size = I.
getSize();
366 unsigned int step = image_size / nbThreads;
367 unsigned int last_step = image_size - step * (nbThreads - 1);
369 for (
unsigned int index = 0; index < nbThreads; ++index) {
370 unsigned int start_index = index * step;
371 unsigned int end_index = (index + 1) * step;
373 if (index == nbThreads - 1) {
374 end_index = start_index + last_step;
377 vpHistogram_Param_t *histogram_param =
new vpHistogram_Param_t(start_index, end_index, &I, mp_mask);
378 histogram_param->m_histogram =
new unsigned int[m_size];
379 histogram_param->m_mask = mp_mask;
380 memset(histogram_param->m_histogram, 0, m_size *
sizeof(
unsigned int));
381 memcpy(histogram_param->m_lut, lut, 256 *
sizeof(
unsigned int));
383 histogramParams.push_back(histogram_param);
386 std::thread *histogram_thread =
new std::thread(&computeHistogramThread, histogram_param);
387 threadpool.push_back(histogram_thread);
390 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
392 threadpool[cpt]->join();
396 for (
unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
397 unsigned int sum = 0;
399 for (
size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
400 sum += histogramParams[cpt2]->m_histogram[cpt1];
403 m_histogram[cpt1] = sum;
408 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
409 delete threadpool[cpt];
412 for (
size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
413 delete histogramParams[cpt];
425 unsigned int cdf[256];
426 unsigned int cdfMin = std::numeric_limits<unsigned int>::max(), cdfMax = 0;
427 unsigned int minValue = std::numeric_limits<unsigned int>::max(), maxValue = 0;
428 cdf[0] = m_histogram[0];
430 if ((cdf[0] < cdfMin) && (cdf[0] > 0)) {
435 const unsigned int val_256 = 256;
436 for (
unsigned int i = 1; i < val_256; ++i) {
437 cdf[i] = cdf[i - 1] + m_histogram[i];
439 if ((cdf[i] < cdfMin) && (cdf[i] > 0)) {
444 if (cdf[i] > cdfMax) {
451 if (nbPixels == cdfMin) {
457 unsigned char lut[256];
458 for (
unsigned int x = minValue; x <= maxValue; ++x) {
459 lut[x] =
vpMath::round(((cdf[x] - cdfMin) /
static_cast<double>(nbPixels - cdfMin)) * 255.0);
478 unsigned int maxValue_)
482 if ((width < 36) || (height < 36)) {
483 std::cerr <<
"Image I must have at least width >= 36 && height >= 36 !" << std::endl;
487 unsigned int maxValue = maxValue_;
489 for (
unsigned int i = 0; i < m_size; ++i) {
490 if (m_histogram[i] > maxValue) {
491 maxValue = m_histogram[i];
500 unsigned int max_height = height - 12;
501 double ratio_height = max_height /
static_cast<double>(maxValue);
502 double ratio_width = (width - 1) /
static_cast<double>(m_size - 1.0);
504 for (
unsigned int i = 1; i < m_size; ++i) {
505 unsigned int value1 = m_histogram[i - 1];
506 unsigned int value2 = m_histogram[i];
508 vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
509 vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
534 if (m_histogram ==
nullptr) {
541 int hsize =
static_cast<int>(fsize) / 2;
543 for (
unsigned i = 0; i < m_size; ++i) {
544 unsigned int sum = 0;
546 for (
int j = -hsize; j <= hsize; ++j) {
548 if ( (i +
static_cast<unsigned int>(j)) < m_size) {
549 sum += h.m_histogram[i +
static_cast<unsigned int>(j)];
553 m_histogram[i] = sum / nb;
573 if (m_histogram ==
nullptr) {
585 unsigned sum_level = 0;
589 for (
unsigned i = 0; i < (m_size - 1); ++i) {
590 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
592 if ((prev_slope > 0) && (next_slope == 0)) {
598 if ((prev_slope > 0) && (next_slope < 0)) {
602 unsigned int level = sum_level / cpt;
603 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
609 prev_slope = next_slope;
614 if (prev_slope > 0) {
615 p.
set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
642 std::list<vpHistogramPeak> peaks;
644 const unsigned int val_2 = 2;
656 peak1 = peaks.front();
663 peak1 = peaks.front();
664 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
665 for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks_end; ++it) {
698 unsigned index_highest_peak;
699 unsigned index_second_peak;
702 unsigned int maxprof;
704 unsigned int sumindmini;
706 unsigned int nbpeaks;
712 peak =
new unsigned char[m_size];
717 for (
unsigned i = 0; i < (m_size - 1); ++i) {
718 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
719 if (next_slope == 0) {
724 if ((prev_slope > 0) && (next_slope < 0)) {
725 peak[nbpeaks++] =
static_cast<unsigned char>(i);
728 prev_slope = next_slope;
731 if (prev_slope > 0) {
732 peak[nbpeaks++] =
static_cast<unsigned char>(m_size - 1);
736 index_highest_peak = 0;
737 for (
unsigned int i = 0; i < nbpeaks; ++i) {
738 if (m_histogram[peak[i]] > m_histogram[peak[index_highest_peak]]) {
739 index_highest_peak = i;
744 index_second_peak = index_highest_peak;
747 for (
unsigned i = 0; i < index_highest_peak; ++i) {
748 if ((peak[index_highest_peak] - peak[i]) > dist) {
750 for (
int j = peak[i]; j <= (peak[index_highest_peak] - dist); ++j) {
751 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
752 prof = m_histogram[peak[i]] - m_histogram[j];
756 if (prof > maxprof) {
758 index_second_peak = i;
764 for (
unsigned i = index_highest_peak + 1; i < nbpeaks; ++i) {
765 if ((peak[i] - peak[index_highest_peak]) > dist) {
767 for (
int j = peak[index_highest_peak] + dist; j <= peak[i]; ++j) {
768 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
769 prof = m_histogram[peak[i]] - m_histogram[j];
773 if (prof > maxprof) {
775 index_second_peak = i;
781 if (peak[index_highest_peak] < peak[index_second_peak]) {
782 peakr.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
783 peakl.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
786 peakl.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
787 peakr.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
790 if (peakl == peakr) {
801 unsigned peakr_level = peakr.
getLevel();
802 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
803 if (m_histogram[i] < mini) {
804 mini = m_histogram[i];
810 if (m_histogram[i] == mini) {
826 mini = sumindmini / nbmini;
827 valey.
set(
static_cast<unsigned char>(mini), m_histogram[mini]);
848 if (m_histogram ==
nullptr) {
860 unsigned sum_level = 0;
864 for (
unsigned i = 0; i < (m_size - 1); ++i) {
865 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
867 if ((prev_slope < 0) && (next_slope == 0)) {
874 if ((prev_slope < 0) && (next_slope > 0)) {
878 unsigned int level = sum_level / cpt;
879 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
885 prev_slope = next_slope;
890 if (prev_slope < 0) {
891 p.
set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
929 unsigned int sumindmini;
935 unsigned peakr_level = peakr.
getLevel();
936 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
937 if (m_histogram[i] < mini) {
938 mini = m_histogram[i];
944 if (m_histogram[i] == mini) {
958 unsigned int minipos = sumindmini / nbmini;
960 valey.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
985 const unsigned int val_ui_0x10 = 0x10;
986 const unsigned int val_ui_0x11 = 0x11;
987 unsigned int ret = 0x11;
989 unsigned int sumindmini;
992 std::list<vpHistogramPeak> peaks;
1000 if (peak.
getLevel() == (m_size - 1)) {
1001 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1008 if (peaks.empty()) {
1013 std::list<vpHistogramPeak>::const_iterator it;
1015 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1016 for (it = peaks.begin(); it != peaks_end; ++it) {
1032 std::list<vpHistogramPeak>::const_iterator lit;
1033 for (lit = peaks.begin(); lit != it; ++lit) {
1034 if (abs((*lit).getLevel() - peak.
getLevel()) > dist) {
1050 unsigned peak_level = peak.
getLevel();
1051 for (
unsigned i = peakl.
getLevel(); i < peak_level; ++i) {
1052 if (m_histogram[i] < mini) {
1053 mini = m_histogram[i];
1059 if (m_histogram[i] == mini) {
1070 unsigned int minipos = sumindmini / nbmini;
1071 valeyl.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1078 if (peaks.empty()) {
1082 std::list<vpHistogramPeak>::const_iterator it;
1083 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1084 for (it = peaks.begin(); it != peaks_end; ++it) {
1093 std::list<vpHistogramPeak>::const_iterator rit;
1094 std::list<vpHistogramPeak>::const_iterator peaks_end_s = peaks.end();
1095 for (rit = it; rit != peaks_end_s; ++rit) {
1097 if (abs((*rit).getLevel() - peak.
getLevel()) > dist) {
1106 peakr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1113 unsigned int peakr_level =
static_cast<unsigned int>(peakr.
getLevel());
1114 for (
unsigned i =
static_cast<unsigned int>(peak.
getLevel()) + 1; i <= peakr_level; ++i) {
1115 if (m_histogram[i] < mini) {
1116 mini = m_histogram[i];
1122 if (m_histogram[i] == mini) {
1129 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1133 unsigned int minipos = sumindmini / nbmini;
1134 valeyr.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1153 if (peaks.empty()) {
1157 peaks.sort(compare_vpHistogramPeak);
1159 return static_cast<unsigned int>(peaks.size());
1190 FILE *fd = fopen(filename,
"w");
1191 if (fd ==
nullptr) {
1194 for (
unsigned i = 0; i < m_size; ++i) {
1195 fprintf(fd,
"%u %u\n", i, m_histogram[i]);
Class to define RGB colors available for display functionalities.
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.
@ divideByZeroError
Division by zero.
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.
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)
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)
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 ...
unsigned int getWidth() const
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
static int round(double x)