46 #include <visp3/core/vpDisplay.h>
47 #include <visp3/core/vpHistogram.h>
48 #include <visp3/core/vpImageConvert.h>
50 #if defined(VISP_HAVE_THREADS)
55 struct vpHistogram_Param_t
57 unsigned int m_start_index;
58 unsigned int m_end_index;
60 unsigned int m_lut[256];
61 unsigned int *m_histogram;
65 vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr), m_mask(nullptr) { }
68 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(nullptr), m_I(I), m_mask(mask)
71 ~vpHistogram_Param_t()
73 if (m_histogram !=
nullptr) {
79 void computeHistogramThread(vpHistogram_Param_t *histogram_param)
81 unsigned int start_index = histogram_param->m_start_index;
82 unsigned int end_index = histogram_param->m_end_index;
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;
90 const bool alwaysTrue =
true;
91 const bool *ptrMaskCurrent = &alwaysTrue;
92 if (histogram_param->m_mask) {
93 ptrMaskCurrent = (
const bool *)histogram_param->m_mask->bitmap + start_index;
96 if (end_index >= 8 + start_index) {
98 for (; ptrCurrent <= ptrEnd - 8;) {
99 if (*ptrMaskCurrent) {
100 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
103 if (histogram_param->m_mask !=
nullptr) {
107 if (*ptrMaskCurrent) {
108 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
111 if (histogram_param->m_mask !=
nullptr) {
115 if (*ptrMaskCurrent) {
116 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
119 if (histogram_param->m_mask !=
nullptr) {
123 if (*ptrMaskCurrent) {
124 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
127 if (histogram_param->m_mask !=
nullptr) {
131 if (*ptrMaskCurrent) {
132 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
135 if (histogram_param->m_mask !=
nullptr) {
139 if (*ptrMaskCurrent) {
140 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
143 if (histogram_param->m_mask !=
nullptr) {
147 if (*ptrMaskCurrent) {
148 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
151 if (histogram_param->m_mask !=
nullptr) {
155 if (*ptrMaskCurrent) {
156 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
159 if (histogram_param->m_mask !=
nullptr) {
165 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
166 if (*ptrMaskCurrent) {
167 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
169 if (histogram_param->m_mask !=
nullptr) {
201 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
238 if (m_histogram !=
nullptr) {
239 delete[] m_histogram;
240 m_histogram =
nullptr;
261 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
273 void vpHistogram::init(
unsigned size_)
275 if (m_histogram !=
nullptr) {
276 delete[] m_histogram;
277 m_histogram =
nullptr;
280 this->m_size = size_;
281 m_histogram =
new unsigned[m_size];
283 memset(m_histogram, 0, m_size *
sizeof(
unsigned));
299 if (m_size != nbins) {
300 if (m_histogram !=
nullptr) {
301 delete[] m_histogram;
302 m_histogram =
nullptr;
305 m_size = nbins > 256 ? 256 : (nbins > 0 ? nbins : 256);
306 if ((nbins > 256) || (nbins == 0)) {
307 std::cerr <<
"nbins=" << nbins <<
" , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
309 m_histogram =
new unsigned int[m_size];
312 memset(m_histogram, 0, m_size *
sizeof(
unsigned int));
314 bool use_single_thread;
315 #if !defined(VISP_HAVE_THREADS)
316 use_single_thread =
true;
318 use_single_thread = (nbThreads == 0 || nbThreads == 1);
321 if ((!use_single_thread) && (I.
getSize() <= nbThreads)) {
322 use_single_thread =
true;
325 unsigned int lut[256];
326 for (
unsigned int i = 0; i < 256; ++i) {
327 lut[i] =
static_cast<unsigned int>((i * m_size) / 256.0);
330 if (use_single_thread) {
332 const bool alwaysTrue =
true;
333 const bool *ptrMaskCurrent = &alwaysTrue;
335 ptrMaskCurrent =
static_cast<const bool *
>(mp_mask->
bitmap);
339 unsigned char *ptrStart =
static_cast<unsigned char *
>(I.
bitmap);
340 unsigned char *ptrEnd = ptrStart + size_;
341 unsigned char *ptrCurrent = ptrStart;
344 while (ptrCurrent != ptrEnd) {
345 if (*ptrMaskCurrent) {
346 ++m_histogram[lut[*ptrCurrent]];
356 #if defined(VISP_HAVE_THREADS)
358 std::vector<std::thread *> threadpool;
359 std::vector<vpHistogram_Param_t *> histogramParams;
361 unsigned int image_size = I.
getSize();
362 unsigned int step = image_size / nbThreads;
363 unsigned int last_step = image_size - step * (nbThreads - 1);
365 for (
unsigned int index = 0; index < nbThreads; ++index) {
366 unsigned int start_index = index * step;
367 unsigned int end_index = (index + 1) * step;
369 if (index == nbThreads - 1) {
370 end_index = start_index + last_step;
373 vpHistogram_Param_t *histogram_param =
new vpHistogram_Param_t(start_index, end_index, &I, mp_mask);
374 histogram_param->m_histogram =
new unsigned int[m_size];
375 histogram_param->m_mask = mp_mask;
376 memset(histogram_param->m_histogram, 0, m_size *
sizeof(
unsigned int));
377 memcpy(histogram_param->m_lut, lut, 256 *
sizeof(
unsigned int));
379 histogramParams.push_back(histogram_param);
382 std::thread *histogram_thread =
new std::thread(&computeHistogramThread, histogram_param);
383 threadpool.push_back(histogram_thread);
386 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
388 threadpool[cpt]->join();
392 for (
unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
393 unsigned int sum = 0;
395 for (
size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
396 sum += histogramParams[cpt2]->m_histogram[cpt1];
399 m_histogram[cpt1] = sum;
404 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
405 delete threadpool[cpt];
408 for (
size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
409 delete histogramParams[cpt];
421 unsigned int cdf[256];
422 unsigned int cdfMin = std::numeric_limits<unsigned int>::max(), cdfMax = 0;
423 unsigned int minValue = std::numeric_limits<unsigned int>::max(), maxValue = 0;
424 cdf[0] = m_histogram[0];
426 if ((cdf[0] < cdfMin) && (cdf[0] > 0)) {
431 for (
unsigned int i = 1; i < 256; ++i) {
432 cdf[i] = cdf[i - 1] + m_histogram[i];
434 if ((cdf[i] < cdfMin) && (cdf[i] > 0)) {
439 if (cdf[i] > cdfMax) {
446 if (nbPixels == cdfMin) {
452 unsigned char lut[256];
453 for (
unsigned int x = minValue; x <= maxValue; ++x) {
454 lut[x] =
vpMath::round((cdf[x] - cdfMin) /
static_cast<double>(nbPixels - cdfMin) * 255.0);
473 unsigned int maxValue_)
477 if ((width < 36) || (height < 36)) {
478 std::cerr <<
"Image I must have at least width >= 36 && height >= 36 !" << std::endl;
482 unsigned int maxValue = maxValue_;
484 for (
unsigned int i = 0; i < m_size; ++i) {
485 if (m_histogram[i] > maxValue) {
486 maxValue = m_histogram[i];
495 unsigned int max_height = height - 12;
496 double ratio_height = max_height /
static_cast<double>(maxValue);
497 double ratio_width = (width - 1) /
static_cast<double>(m_size - 1.0);
499 for (
unsigned int i = 1; i < m_size; ++i) {
500 unsigned int value1 = m_histogram[i - 1];
501 unsigned int value2 = m_histogram[i];
503 vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
504 vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
529 if (m_histogram ==
nullptr) {
537 int hsize =
static_cast<int>(fsize) / 2;
539 for (
unsigned i = 0; i < m_size; ++i) {
540 unsigned int sum = 0;
542 for (
int j = -hsize; j <= hsize; ++j) {
544 if ( (i +
static_cast<unsigned int>(j)) < m_size) {
545 sum += h.m_histogram[i +
static_cast<unsigned int>(j)];
549 m_histogram[i] = sum / nb;
569 if (m_histogram ==
nullptr) {
582 unsigned sum_level = 0;
586 for (
unsigned i = 0; i < (m_size - 1); ++i) {
587 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
589 if ((prev_slope > 0) && (next_slope == 0)) {
596 if ((prev_slope > 0) && (next_slope < 0)) {
600 unsigned int level = sum_level / cpt;
601 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
607 prev_slope = next_slope;
611 if (prev_slope > 0) {
612 p.
set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
639 std::list<vpHistogramPeak> peaks;
652 peak1 = peaks.front();
659 peak1 = peaks.front();
660 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
661 for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks_end; ++it) {
694 unsigned index_highest_peak;
695 unsigned index_second_peak;
698 unsigned int maxprof;
700 unsigned int sumindmini;
702 unsigned int nbpeaks;
708 peak =
new unsigned char[m_size];
713 for (
unsigned i = 0; i < (m_size - 1); ++i) {
714 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
715 if (next_slope == 0) {
719 if ((prev_slope > 0) && (next_slope < 0)) {
720 peak[nbpeaks++] =
static_cast<unsigned char>(i);
723 prev_slope = next_slope;
725 if (prev_slope > 0) {
726 peak[nbpeaks++] =
static_cast<unsigned char>(m_size - 1);
730 index_highest_peak = 0;
731 for (
unsigned int i = 0; i < nbpeaks; ++i) {
732 if (m_histogram[peak[i]] > m_histogram[peak[index_highest_peak]]) {
733 index_highest_peak = i;
738 index_second_peak = index_highest_peak;
741 for (
unsigned i = 0; i < index_highest_peak; ++i) {
742 if ((peak[index_highest_peak] - peak[i]) > dist) {
744 for (
int j = peak[i]; j <= (peak[index_highest_peak] - dist); ++j) {
745 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
746 prof = m_histogram[peak[i]] - m_histogram[j];
750 if (prof > maxprof) {
752 index_second_peak = i;
758 for (
unsigned i = index_highest_peak + 1; i < nbpeaks; ++i) {
759 if ((peak[i] - peak[index_highest_peak]) > dist) {
761 for (
int j = peak[index_highest_peak] + dist; j <= peak[i]; ++j) {
762 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
763 prof = m_histogram[peak[i]] - m_histogram[j];
767 if (prof > maxprof) {
769 index_second_peak = i;
775 if (peak[index_highest_peak] < peak[index_second_peak]) {
776 peakr.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
777 peakl.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
780 peakl.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
781 peakr.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
784 if (peakl == peakr) {
795 unsigned peakr_level = peakr.
getLevel();
796 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
797 if (m_histogram[i] < mini) {
798 mini = m_histogram[i];
803 if (m_histogram[i] == mini) {
818 mini = sumindmini / nbmini;
819 valey.
set(
static_cast<unsigned char>(mini), m_histogram[mini]);
840 if (m_histogram ==
nullptr) {
853 unsigned sum_level = 0;
857 for (
unsigned i = 0; i < (m_size - 1); ++i) {
858 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
860 if ((prev_slope < 0) && (next_slope == 0)) {
867 if ((prev_slope < 0) && (next_slope > 0)) {
871 unsigned int level = sum_level / cpt;
872 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
878 prev_slope = next_slope;
882 if (prev_slope < 0) {
883 p.
set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
921 unsigned int sumindmini;
927 unsigned peakr_level = peakr.
getLevel();
928 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
929 if (m_histogram[i] < mini) {
930 mini = m_histogram[i];
935 if (m_histogram[i] == mini) {
948 unsigned int minipos = sumindmini / nbmini;
950 valey.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
975 unsigned int ret = 0x11;
977 unsigned int sumindmini;
980 std::list<vpHistogramPeak> peaks;
988 if (peak.
getLevel() == (m_size - 1)) {
989 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1001 std::list<vpHistogramPeak>::const_iterator it;
1003 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1004 for (it = peaks.begin(); it != peaks_end; ++it) {
1020 std::list<vpHistogramPeak>::const_iterator lit;
1021 for (lit = peaks.begin(); lit != it; ++lit) {
1022 if (abs((*lit).getLevel() - peak.
getLevel()) > dist) {
1038 unsigned peak_level = peak.
getLevel();
1039 for (
unsigned i = peakl.
getLevel(); i < peak_level; ++i) {
1040 if (m_histogram[i] < mini) {
1041 mini = m_histogram[i];
1046 if (m_histogram[i] == mini) {
1056 unsigned int minipos = sumindmini / nbmini;
1057 valeyl.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1064 if (peaks.empty()) {
1068 std::list<vpHistogramPeak>::const_iterator it;
1069 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1070 for (it = peaks.begin(); it != peaks_end; ++it) {
1079 std::list<vpHistogramPeak>::const_iterator rit;
1080 std::list<vpHistogramPeak>::const_iterator peaks_end_s = peaks.end();
1081 for (rit = it; rit != peaks_end_s; ++rit) {
1083 if (abs((*rit).getLevel() - peak.
getLevel()) > dist) {
1092 peakr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1099 unsigned int peakr_level =
static_cast<unsigned int>(peakr.
getLevel());
1100 for (
unsigned i =
static_cast<unsigned int>(peak.
getLevel()) + 1; i <= peakr_level; ++i) {
1101 if (m_histogram[i] < mini) {
1102 mini = m_histogram[i];
1107 if (m_histogram[i] == mini) {
1113 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1117 unsigned int minipos = sumindmini / nbmini;
1118 valeyr.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1137 if (peaks.empty()) {
1141 peaks.sort(compare_vpHistogramPeak);
1143 return static_cast<unsigned int>(peaks.size());
1174 FILE *fd = fopen(filename,
"w");
1175 if (fd ==
nullptr) {
1178 for (
unsigned i = 0; i < m_size; ++i) {
1179 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)