45 #include <visp3/core/vpDisplay.h>
46 #include <visp3/core/vpHistogram.h>
47 #include <visp3/core/vpImageConvert.h>
50 #if defined(VISP_HAVE_THREADS)
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
56 struct vpHistogram_Param_t
58 unsigned int m_start_index;
59 unsigned int m_end_index;
61 unsigned int m_lut[256];
62 unsigned int *m_histogram;
66 vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr), m_mask(nullptr) { }
69 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_histogram(nullptr), m_I(I), m_mask(mask)
72 ~vpHistogram_Param_t()
74 if (m_histogram !=
nullptr) {
80 void computeHistogramThread(vpHistogram_Param_t *histogram_param)
82 unsigned int start_index = histogram_param->m_start_index;
83 unsigned int end_index = histogram_param->m_end_index;
87 unsigned char *ptrStart = (
unsigned char *)(I->
bitmap) + start_index;
88 unsigned char *ptrEnd = (
unsigned char *)(I->
bitmap) + end_index;
89 unsigned char *ptrCurrent = ptrStart;
91 const bool alwaysTrue =
true;
92 const bool *ptrMaskCurrent = &alwaysTrue;
93 if (histogram_param->m_mask) {
94 ptrMaskCurrent = (
const bool *)histogram_param->m_mask->bitmap + start_index;
97 if (end_index >= 8 + start_index) {
99 for (; ptrCurrent <= ptrEnd - 8;) {
100 if (*ptrMaskCurrent) {
101 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
104 if (histogram_param->m_mask !=
nullptr) {
108 if (*ptrMaskCurrent) {
109 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
112 if (histogram_param->m_mask !=
nullptr) {
116 if (*ptrMaskCurrent) {
117 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
120 if (histogram_param->m_mask !=
nullptr) {
124 if (*ptrMaskCurrent) {
125 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
128 if (histogram_param->m_mask !=
nullptr) {
132 if (*ptrMaskCurrent) {
133 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
136 if (histogram_param->m_mask !=
nullptr) {
140 if (*ptrMaskCurrent) {
141 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
144 if (histogram_param->m_mask !=
nullptr) {
148 if (*ptrMaskCurrent) {
149 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
152 if (histogram_param->m_mask !=
nullptr) {
156 if (*ptrMaskCurrent) {
157 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
160 if (histogram_param->m_mask !=
nullptr) {
166 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
167 if (*ptrMaskCurrent) {
168 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
170 if (histogram_param->m_mask !=
nullptr) {
203 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
240 if (m_histogram !=
nullptr) {
241 delete[] m_histogram;
242 m_histogram =
nullptr;
263 memcpy(m_histogram, h.m_histogram, m_size *
sizeof(
unsigned));
275 void vpHistogram::init(
unsigned size_)
277 if (m_histogram !=
nullptr) {
278 delete[] m_histogram;
279 m_histogram =
nullptr;
282 this->m_size = size_;
283 m_histogram =
new unsigned[m_size];
285 memset(m_histogram, 0, m_size *
sizeof(
unsigned));
301 if (m_size != nbins) {
302 if (m_histogram !=
nullptr) {
303 delete[] m_histogram;
304 m_histogram =
nullptr;
307 m_size = nbins > 256 ? 256 : (nbins > 0 ? nbins : 256);
308 if ((nbins > 256) || (nbins == 0)) {
309 std::cerr <<
"nbins=" << nbins <<
" , nbins should be between ]0 ; 256] ; use by default nbins=256" << std::endl;
311 m_histogram =
new unsigned int[m_size];
314 memset(m_histogram, 0, m_size *
sizeof(
unsigned int));
316 bool use_single_thread;
317 #if !defined(VISP_HAVE_THREADS)
318 use_single_thread =
true;
320 use_single_thread = (nbThreads == 0 || nbThreads == 1);
323 if ((!use_single_thread) && (I.
getSize() <= nbThreads)) {
324 use_single_thread =
true;
327 unsigned int lut[256];
328 for (
unsigned int i = 0; i < 256; ++i) {
329 lut[i] =
static_cast<unsigned int>((i * m_size) / 256.0);
332 if (use_single_thread) {
334 const bool alwaysTrue =
true;
335 const bool *ptrMaskCurrent = &alwaysTrue;
337 ptrMaskCurrent =
static_cast<const bool *
>(mp_mask->
bitmap);
341 unsigned char *ptrStart =
static_cast<unsigned char *
>(I.
bitmap);
342 unsigned char *ptrEnd = ptrStart + size_;
343 unsigned char *ptrCurrent = ptrStart;
346 while (ptrCurrent != ptrEnd) {
347 if (*ptrMaskCurrent) {
348 ++m_histogram[lut[*ptrCurrent]];
358 #if defined(VISP_HAVE_THREADS)
360 std::vector<std::thread *> threadpool;
361 std::vector<vpHistogram_Param_t *> histogramParams;
363 unsigned int image_size = I.
getSize();
364 unsigned int step = image_size / nbThreads;
365 unsigned int last_step = image_size - step * (nbThreads - 1);
367 for (
unsigned int index = 0; index < nbThreads; ++index) {
368 unsigned int start_index = index * step;
369 unsigned int end_index = (index + 1) * step;
371 if (index == nbThreads - 1) {
372 end_index = start_index + last_step;
375 vpHistogram_Param_t *histogram_param =
new vpHistogram_Param_t(start_index, end_index, &I, mp_mask);
376 histogram_param->m_histogram =
new unsigned int[m_size];
377 histogram_param->m_mask = mp_mask;
378 memset(histogram_param->m_histogram, 0, m_size *
sizeof(
unsigned int));
379 memcpy(histogram_param->m_lut, lut, 256 *
sizeof(
unsigned int));
381 histogramParams.push_back(histogram_param);
384 std::thread *histogram_thread =
new std::thread(&computeHistogramThread, histogram_param);
385 threadpool.push_back(histogram_thread);
388 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
390 threadpool[cpt]->join();
394 for (
unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
395 unsigned int sum = 0;
397 for (
size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
398 sum += histogramParams[cpt2]->m_histogram[cpt1];
401 m_histogram[cpt1] = sum;
406 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
407 delete threadpool[cpt];
410 for (
size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
411 delete histogramParams[cpt];
423 unsigned int cdf[256];
424 unsigned int cdfMin = std::numeric_limits<unsigned int>::max(), cdfMax = 0;
425 unsigned int minValue = std::numeric_limits<unsigned int>::max(), maxValue = 0;
426 cdf[0] = m_histogram[0];
428 if ((cdf[0] < cdfMin) && (cdf[0] > 0)) {
433 for (
unsigned int i = 1; i < 256; ++i) {
434 cdf[i] = cdf[i - 1] + m_histogram[i];
436 if ((cdf[i] < cdfMin) && (cdf[i] > 0)) {
441 if (cdf[i] > cdfMax) {
448 if (nbPixels == cdfMin) {
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);
475 unsigned int maxValue_)
479 if ((width < 36) || (height < 36)) {
480 std::cerr <<
"Image I must have at least width >= 36 && height >= 36 !" << std::endl;
484 unsigned int maxValue = maxValue_;
486 for (
unsigned int i = 0; i < m_size; ++i) {
487 if (m_histogram[i] > maxValue) {
488 maxValue = m_histogram[i];
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);
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];
505 vpImagePoint startPt((height - 1) - (value1 * ratio_height), (i - 1) * ratio_width);
506 vpImagePoint endPt((height - 1) - (value2 * ratio_height), (i * ratio_width));
531 if (m_histogram ==
nullptr) {
538 int hsize =
static_cast<int>(fsize) / 2;
540 for (
unsigned i = 0; i < m_size; ++i) {
541 unsigned int sum = 0;
543 for (
int j = -hsize; j <= hsize; ++j) {
545 if ( (i +
static_cast<unsigned int>(j)) < m_size) {
546 sum += h.m_histogram[i +
static_cast<unsigned int>(j)];
550 m_histogram[i] = sum / nb;
570 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)) {
595 if ((prev_slope > 0) && (next_slope < 0)) {
599 unsigned int level = sum_level / cpt;
600 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
606 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) {
720 if ((prev_slope > 0) && (next_slope < 0)) {
721 peak[nbpeaks++] =
static_cast<unsigned char>(i);
724 prev_slope = next_slope;
727 if (prev_slope > 0) {
728 peak[nbpeaks++] =
static_cast<unsigned char>(m_size - 1);
732 index_highest_peak = 0;
733 for (
unsigned int i = 0; i < nbpeaks; ++i) {
734 if (m_histogram[peak[i]] > m_histogram[peak[index_highest_peak]]) {
735 index_highest_peak = i;
740 index_second_peak = index_highest_peak;
743 for (
unsigned i = 0; i < index_highest_peak; ++i) {
744 if ((peak[index_highest_peak] - peak[i]) > dist) {
746 for (
int j = peak[i]; j <= (peak[index_highest_peak] - dist); ++j) {
747 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
748 prof = m_histogram[peak[i]] - m_histogram[j];
752 if (prof > maxprof) {
754 index_second_peak = i;
760 for (
unsigned i = index_highest_peak + 1; i < nbpeaks; ++i) {
761 if ((peak[i] - peak[index_highest_peak]) > dist) {
763 for (
int j = peak[index_highest_peak] + dist; j <= peak[i]; ++j) {
764 if ((m_histogram[peak[i]] - m_histogram[j]) > prof) {
765 prof = m_histogram[peak[i]] - m_histogram[j];
769 if (prof > maxprof) {
771 index_second_peak = i;
777 if (peak[index_highest_peak] < peak[index_second_peak]) {
778 peakr.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
779 peakl.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
782 peakl.
set(peak[index_second_peak], m_histogram[peak[index_second_peak]]);
783 peakr.
set(peak[index_highest_peak], m_histogram[peak[index_highest_peak]]);
786 if (peakl == peakr) {
797 unsigned peakr_level = peakr.
getLevel();
798 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
799 if (m_histogram[i] < mini) {
800 mini = m_histogram[i];
806 if (m_histogram[i] == mini) {
822 mini = sumindmini / nbmini;
823 valey.
set(
static_cast<unsigned char>(mini), m_histogram[mini]);
844 if (m_histogram ==
nullptr) {
856 unsigned sum_level = 0;
860 for (
unsigned i = 0; i < (m_size - 1); ++i) {
861 int next_slope =
static_cast<int>(m_histogram[i + 1]) -
static_cast<int>(m_histogram[i]);
863 if ((prev_slope < 0) && (next_slope == 0)) {
870 if ((prev_slope < 0) && (next_slope > 0)) {
874 unsigned int level = sum_level / cpt;
875 p.
set(
static_cast<unsigned char>(level), m_histogram[level]);
881 prev_slope = next_slope;
886 if (prev_slope < 0) {
887 p.
set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
925 unsigned int sumindmini;
931 unsigned peakr_level = peakr.
getLevel();
932 for (
unsigned i = peakl.
getLevel(); i <= peakr_level; ++i) {
933 if (m_histogram[i] < mini) {
934 mini = m_histogram[i];
940 if (m_histogram[i] == mini) {
954 unsigned int minipos = sumindmini / nbmini;
956 valey.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
981 unsigned int ret = 0x11;
983 unsigned int sumindmini;
986 std::list<vpHistogramPeak> peaks;
994 if (peak.
getLevel() == (m_size - 1)) {
995 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1002 if (peaks.empty()) {
1007 std::list<vpHistogramPeak>::const_iterator it;
1009 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1010 for (it = peaks.begin(); it != peaks_end; ++it) {
1026 std::list<vpHistogramPeak>::const_iterator lit;
1027 for (lit = peaks.begin(); lit != it; ++lit) {
1028 if (abs((*lit).getLevel() - peak.
getLevel()) > dist) {
1044 unsigned peak_level = peak.
getLevel();
1045 for (
unsigned i = peakl.
getLevel(); i < peak_level; ++i) {
1046 if (m_histogram[i] < mini) {
1047 mini = m_histogram[i];
1053 if (m_histogram[i] == mini) {
1064 unsigned int minipos = sumindmini / nbmini;
1065 valeyl.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1072 if (peaks.empty()) {
1076 std::list<vpHistogramPeak>::const_iterator it;
1077 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1078 for (it = peaks.begin(); it != peaks_end; ++it) {
1087 std::list<vpHistogramPeak>::const_iterator rit;
1088 std::list<vpHistogramPeak>::const_iterator peaks_end_s = peaks.end();
1089 for (rit = it; rit != peaks_end_s; ++rit) {
1091 if (abs((*rit).getLevel() - peak.
getLevel()) > dist) {
1100 peakr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1107 unsigned int peakr_level =
static_cast<unsigned int>(peakr.
getLevel());
1108 for (
unsigned i =
static_cast<unsigned int>(peak.
getLevel()) + 1; i <= peakr_level; ++i) {
1109 if (m_histogram[i] < mini) {
1110 mini = m_histogram[i];
1116 if (m_histogram[i] == mini) {
1123 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1127 unsigned int minipos = sumindmini / nbmini;
1128 valeyr.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1147 if (peaks.empty()) {
1151 peaks.sort(compare_vpHistogramPeak);
1153 return static_cast<unsigned int>(peaks.size());
1184 FILE *fd = fopen(filename,
"w");
1185 if (fd ==
nullptr) {
1188 for (
unsigned i = 0; i < m_size; ++i) {
1189 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)