44#include <visp3/core/vpDisplay.h>
45#include <visp3/core/vpHistogram.h>
46#include <visp3/core/vpImageConvert.h>
49const unsigned int vpHistogram::constr_val_256 = 256;
50#if defined(VISP_HAVE_THREADS)
51#ifndef DOXYGEN_SHOULD_SKIP_THIS
54struct vpHistogram_Param_t
56 unsigned int m_start_index;
57 unsigned int m_end_index;
59 unsigned int m_lut[256];
60 unsigned int *m_histogram;
61 const vpImage<unsigned char> *m_I;
62 const vpImage<bool> *m_mask;
64 vpHistogram_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_histogram(nullptr), m_I(nullptr), m_mask(nullptr) { }
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)
70 ~vpHistogram_Param_t()
72 if (m_histogram !=
nullptr) {
78void computeHistogramThread(vpHistogram_Param_t *histogram_param)
80 unsigned int start_index = histogram_param->m_start_index;
81 unsigned int end_index = histogram_param->m_end_index;
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;
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;
95 if (end_index >= 8 + start_index) {
97 for (; ptrCurrent <= ptrEnd - 8;) {
98 if (*ptrMaskCurrent) {
99 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
102 if (histogram_param->m_mask !=
nullptr) {
106 if (*ptrMaskCurrent) {
107 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
110 if (histogram_param->m_mask !=
nullptr) {
114 if (*ptrMaskCurrent) {
115 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
118 if (histogram_param->m_mask !=
nullptr) {
122 if (*ptrMaskCurrent) {
123 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
126 if (histogram_param->m_mask !=
nullptr) {
130 if (*ptrMaskCurrent) {
131 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
134 if (histogram_param->m_mask !=
nullptr) {
138 if (*ptrMaskCurrent) {
139 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
142 if (histogram_param->m_mask !=
nullptr) {
146 if (*ptrMaskCurrent) {
147 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
150 if (histogram_param->m_mask !=
nullptr) {
154 if (*ptrMaskCurrent) {
155 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
158 if (histogram_param->m_mask !=
nullptr) {
164 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
165 if (*ptrMaskCurrent) {
166 histogram_param->m_histogram[histogram_param->m_lut[*ptrCurrent]]++;
168 if (histogram_param->m_mask !=
nullptr) {
193vpHistogram::vpHistogram(
const unsigned int &size) : m_histogram(nullptr), m_size(size), mp_mask(nullptr), m_total(0) { init(size); }
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));
273void 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 const unsigned int val_256 = 256;
300 if (m_size != nbins) {
301 if (m_histogram !=
nullptr) {
302 delete[] m_histogram;
303 m_histogram =
nullptr;
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;
310 m_histogram =
new unsigned int[m_size];
313 memset(m_histogram, 0, m_size *
sizeof(
unsigned int));
315 bool use_single_thread;
316#if !defined(VISP_HAVE_THREADS)
317 use_single_thread =
true;
319 use_single_thread = (nbThreads == 0 || nbThreads == 1);
322 if ((!use_single_thread) && (I.getSize() <= nbThreads)) {
323 use_single_thread =
true;
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);
331 if (use_single_thread) {
333 const bool alwaysTrue =
true;
334 const bool *ptrMaskCurrent = &alwaysTrue;
336 ptrMaskCurrent =
static_cast<const bool *
>(mp_mask->bitmap);
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;
345 while (ptrCurrent != ptrEnd) {
346 if (*ptrMaskCurrent) {
347 ++m_histogram[lut[*ptrCurrent]];
357#if defined(VISP_HAVE_THREADS)
359 std::vector<std::thread *> threadpool;
360 std::vector<vpHistogram_Param_t *> histogramParams;
362 unsigned int image_size = I.getSize();
363 unsigned int step = image_size / nbThreads;
364 unsigned int last_step = image_size - step * (nbThreads - 1);
366 for (
unsigned int index = 0; index < nbThreads; ++index) {
367 unsigned int start_index = index * step;
368 unsigned int end_index = (index + 1) * step;
370 if (index == nbThreads - 1) {
371 end_index = start_index + last_step;
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));
380 histogramParams.push_back(histogram_param);
383 std::thread *histogram_thread =
new std::thread(&computeHistogramThread, histogram_param);
384 threadpool.push_back(histogram_thread);
387 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
389 threadpool[cpt]->join();
393 for (
unsigned int cpt1 = 0; cpt1 < m_size; ++cpt1) {
394 unsigned int sum = 0;
396 for (
size_t cpt2 = 0; cpt2 < histogramParams.size(); ++cpt2) {
397 sum += histogramParams[cpt2]->m_histogram[cpt1];
400 m_histogram[cpt1] = sum;
405 for (
size_t cpt = 0; cpt < threadpool.size(); ++cpt) {
406 delete threadpool[cpt];
409 for (
size_t cpt = 0; cpt < histogramParams.size(); ++cpt) {
410 delete histogramParams[cpt];
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];
427 if ((cdf[0] < cdfMin) && (cdf[0] > 0)) {
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];
436 if ((cdf[i] < cdfMin) && (cdf[i] > 0)) {
441 if (cdf[i] > cdfMax) {
447 unsigned int nbPixels = I.getWidth() * I.getHeight();
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_)
477 unsigned int width = I.getWidth(), height = I.getHeight();
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 unsigned int hsize = fsize / 2;
539 unsigned int sizeAsInt = m_size;
541 for (
unsigned int i = 0; i < sizeAsInt; ++i) {
542 unsigned int sum = 0;
544 for (
unsigned int j = 0; j <= hsize; ++j) {
546 if ((i - j) < sizeAsInt) {
547 sum += h.m_histogram[i - j];
550 if ((i + j) < sizeAsInt) {
551 sum += h.m_histogram[i + j];
555 m_histogram[i] = sum / nb;
575 if (m_histogram ==
nullptr) {
587 unsigned sum_level = 0;
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]);
594 if ((prev_slope > 0) && (next_slope == 0)) {
600 if ((prev_slope > 0) && (next_slope < 0)) {
604 unsigned int level = sum_level / cpt;
605 p.set(
static_cast<unsigned char>(level), m_histogram[level]);
611 prev_slope = next_slope;
616 if (prev_slope > 0) {
617 p.set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
644 std::list<vpHistogramPeak> peaks;
646 const unsigned int val_2 = 2;
658 peak1 = peaks.front();
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) {
669 if (abs(p.getLevel() - peak1.
getLevel()) > dist) {
700 unsigned index_highest_peak;
701 unsigned index_second_peak;
704 unsigned int maxprof;
706 unsigned int sumindmini;
708 unsigned int nbpeaks;
714 peak =
new unsigned char[m_size];
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]);
721 if (next_slope == 0) {
726 if ((prev_slope > 0) && (next_slope < 0)) {
727 peak[nbpeaks++] =
static_cast<unsigned char>(i);
730 prev_slope = next_slope;
733 if (prev_slope > 0) {
734 peak[nbpeaks++] =
static_cast<unsigned char>(m_size - 1);
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;
746 index_second_peak = index_highest_peak;
749 for (
unsigned i = 0; i < index_highest_peak; ++i) {
750 if ((peak[index_highest_peak] - peak[i]) > dist) {
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];
758 if (prof > maxprof) {
760 index_second_peak = i;
766 for (
unsigned i = index_highest_peak + 1; i < nbpeaks; ++i) {
767 if ((peak[i] - peak[index_highest_peak]) > dist) {
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];
775 if (prof > maxprof) {
777 index_second_peak = i;
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]]);
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]]);
792 if (peakl == peakr) {
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];
812 if (m_histogram[i] == mini) {
828 mini = sumindmini / nbmini;
829 valey.
set(
static_cast<unsigned char>(mini), m_histogram[mini]);
850 if (m_histogram ==
nullptr) {
862 unsigned sum_level = 0;
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]);
869 if ((prev_slope < 0) && (next_slope == 0)) {
876 if ((prev_slope < 0) && (next_slope > 0)) {
880 unsigned int level = sum_level / cpt;
881 p.set(
static_cast<unsigned char>(level), m_histogram[level]);
887 prev_slope = next_slope;
892 if (prev_slope < 0) {
893 p.set(
static_cast<unsigned char>(m_size) - 1u, m_histogram[m_size - 1]);
931 unsigned int sumindmini;
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];
946 if (m_histogram[i] == mini) {
960 unsigned int minipos = sumindmini / nbmini;
962 valey.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
987 const unsigned int val_ui_0x10 = 0x10;
988 const unsigned int val_ui_0x11 = 0x11;
989 unsigned int ret = 0x11;
991 unsigned int sumindmini;
994 std::list<vpHistogramPeak> peaks;
1002 if (peak.
getLevel() == (m_size - 1)) {
1003 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1010 if (peaks.empty()) {
1015 std::list<vpHistogramPeak>::const_iterator it;
1017 std::list<vpHistogramPeak>::const_iterator peaks_end = peaks.end();
1018 for (it = peaks.begin(); it != peaks_end; ++it) {
1034 std::list<vpHistogramPeak>::const_iterator lit;
1035 for (lit = peaks.begin(); lit != it; ++lit) {
1036 if (abs((*lit).getLevel() - peak.
getLevel()) > dist) {
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];
1061 if (m_histogram[i] == mini) {
1072 unsigned int minipos = sumindmini / nbmini;
1073 valeyl.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1080 if (peaks.empty()) {
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) {
1095 std::list<vpHistogramPeak>::const_iterator rit;
1096 std::list<vpHistogramPeak>::const_iterator peaks_end_s = peaks.end();
1097 for (rit = it; rit != peaks_end_s; ++rit) {
1099 if (abs((*rit).getLevel() - peak.
getLevel()) > dist) {
1108 peakr.
set(
static_cast<unsigned char>(m_size - 1), 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];
1124 if (m_histogram[i] == mini) {
1131 valeyr.
set(
static_cast<unsigned char>(m_size - 1), 0);
1135 unsigned int minipos = sumindmini / nbmini;
1136 valeyr.
set(
static_cast<unsigned char>(minipos), m_histogram[minipos]);
1155 if (peaks.empty()) {
1159 peaks.sort(compare_vpHistogramPeak);
1161 return static_cast<unsigned int>(peaks.size());
1192 FILE *fd = fopen(filename,
"w");
1193 if (fd ==
nullptr) {
1196 for (
unsigned i = 0; i < m_size; ++i) {
1197 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)
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)
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.
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
static int round(double x)