59 #include <visp3/core/vpGaussianFilter.h>
60 #include <visp3/core/vpHistogram.h>
61 #include <visp3/core/vpImageConvert.h>
62 #include <visp3/core/vpImageFilter.h>
63 #include <visp3/core/vpImageTools.h>
64 #include <visp3/core/vpMath.h>
65 #include <visp3/imgproc/vpImgproc.h>
69 std::string
vpGammaMethodList(
const std::string &pref,
const std::string &sep,
const std::string &suf)
71 std::string list(pref);
88 name =
"gamma_manual";
94 name =
"gamma_nonlinear";
100 name =
"gamma_classification";
103 name =
"gamma_spatial_variant";
107 name =
"gamma_method_unknown";
116 bool notFound =
true;
118 while ((i < count) && notFound) {
131 std::string list(pref);
148 name =
"gamma_color_rgb";
151 name =
"gamma_color_hsv";
155 name =
"gamma_color_unknown";
164 bool notFound =
true;
166 while ((i < count) && notFound) {
180 unsigned char lut[256];
181 for (
unsigned int i = 0; i < 256; ++i) {
182 lut[i] = vpMath::saturate<unsigned char>((alpha * i) + beta);
201 for (
unsigned int i = 0; i < 256; ++i) {
202 lut[i].
R = vpMath::saturate<unsigned char>((alpha * i) + beta);
203 lut[i].
G = vpMath::saturate<unsigned char>((alpha * i) + beta);
204 lut[i].
B = vpMath::saturate<unsigned char>((alpha * i) + beta);
205 lut[i].
A = vpMath::saturate<unsigned char>((alpha * i) + beta);
261 unsigned char *ptrStart = (
unsigned char *)I.
bitmap;
262 unsigned char *ptrEnd = ptrStart + (size * 4);
263 unsigned char *ptrCurrent = ptrStart;
265 unsigned int cpt = 0;
266 while (ptrCurrent != ptrEnd) {
267 *ptrCurrent = pR.
bitmap[cpt];
270 *ptrCurrent = pG.
bitmap[cpt];
273 *ptrCurrent = pB.
bitmap[cpt];
276 *ptrCurrent = pa.
bitmap[cpt];
290 (
unsigned char *)saturation.
bitmap, (
unsigned char *)value.
bitmap, size);
297 (
unsigned char *)value.
bitmap, (
unsigned char *)I.
bitmap, size);
322 float mean =
static_cast<float>(I.
getMeanValue(p_mask));
323 unsigned char inputMin = 0, inputMax = 0;
325 unsigned char inputRange = inputMax - inputMin;
327 float gamma_computed =
static_cast<float>((std::log(128.f) - std::log(256.f)) / (std::log(mean) - std::log(inputRange)));
328 float inverse_gamma = 1.f / gamma_computed;
331 unsigned char lut[256];
332 float inputRangeAsFloat =
static_cast<float>(inputRange);
333 for (
unsigned int i = inputMin; i <= inputMax; ++i) {
334 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i - inputMin) / inputRangeAsFloat, inverse_gamma) * 255.f);
354 const float a = 0.2f;
355 const float b = 0.3f;
356 const float c = 0.3f;
357 const float x_m = 127.5f;
358 const float alpha = std::atan2(-b, x_m);
359 const float rho = 0.1f;
360 unsigned char lut[256];
361 for (
unsigned int i = 0; i < 256; ++i) {
362 float x =
static_cast<float>(i);
363 float phi = (M_PIf * x) / (2.f * x_m);
364 float f1 = a * std::cos(phi);
365 float k = rho * std::sin((4 * M_PIf * x) / 255.f);
366 float f2 = ((k + b)*std::cos(alpha)) + (x * std::sin(alpha));
367 float r = c * std::abs((x / x_m) - 1.f);
368 float f3 = r * std::cos((3.f * M_PIf * x) / 255.f);
369 float g = f1 + f2 + f3;
371 float inverse_gamma = 1.f / gamma;
372 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.f, inverse_gamma) * 255.f);
393 double meanNormalized = mean / 255.;
394 double stdevNormalized = stdev / 255.;
395 const float tau = 3.f;
396 bool isAlreadyHighContrast = (4. * stdevNormalized) > (1./tau);
397 unsigned char lut[256];
399 if (isAlreadyHighContrast) {
401 gamma =
static_cast<float>(std::exp((1.f - (meanNormalized + stdevNormalized))/2.f));
405 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
406 gamma = -
static_cast<float>(std::log2(stdevNormalized));
408 gamma = -
static_cast<float>(std::log(stdevNormalized) / std::log(2));
411 if (meanNormalized < 0.5) {
413 float meanPowerGamma =
static_cast<float>(std::pow(meanNormalized, gamma));
414 for (
unsigned int i = 0; i <= 255; ++i) {
415 float iNormalized =
static_cast<float>(i)/255.f;
416 float iPowerGamma = std::pow(iNormalized, gamma);
417 lut[i] = vpMath::saturate<unsigned char>(255.f * (iPowerGamma / (iPowerGamma + ((1.f - iPowerGamma) * meanPowerGamma))));
422 for (
unsigned int i = 0; i <= 255; ++i) {
423 float iNormalized =
static_cast<float>(i)/255.f;
424 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
444 const unsigned int nbBins = 256;
448 unsigned int totalNbPoints = histo.
getTotal();
449 unsigned int minHisto = histo[0];
450 unsigned int maxHisto = histo[0];
451 for (
unsigned int i = 1; i < nbBins; ++i) {
452 minHisto = std::min(minHisto, histo[i]);
453 maxHisto = std::max(maxHisto, histo[i]);
455 float pdfMin =
static_cast<float>(minHisto) /
static_cast<float>(totalNbPoints);
456 float pdfMax =
static_cast<float>(maxHisto) /
static_cast<float>(totalNbPoints);
458 float sum_pdf_w = 0.f;
459 for (
unsigned int i = 0; i < nbBins; ++i) {
460 float pdf =
static_cast<float>(histo[i])/
static_cast<float>(totalNbPoints);
461 pdf_w[i] = pdfMax * std::sqrt((pdf - pdfMin)/(pdfMax - pdfMin));
462 sum_pdf_w += pdf_w[i];
464 unsigned char lut[256];
466 for (
unsigned int i = 0; i <= 255; ++i) {
467 cdf_w += pdf_w[i] / sum_pdf_w;
468 float gamma = 1.f - cdf_w;
469 float iNormalized =
static_cast<float>(i)/255.f;
470 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
492 const bool normalize =
true;
502 const float alpha = 0.5f;
503 unsigned int size = height * width;
504 float stdev =
static_cast<float>(I.
getStdev(p_mask));
509 else if (stdev <= 80) {
510 p = (-0.025f * stdev) + 3.f;
516 for (
unsigned int i = 0; i < size; ++i) {
517 bool hasToCompute =
true;
518 if (p_mask !=
nullptr) {
519 hasToCompute = p_mask->
bitmap[i];
523 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
524 float iNormalized =
static_cast<float>(I.
bitmap[i])/255.f;
525 float o = std::pow(iNormalized, gamma) * 255.f;
527 float e = std::pow(r, p);
528 float s = 255.f * std::pow(o / 255.f, e);
529 I.
bitmap[i] = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i])) / o);
546 unsigned int size = height * width;
548 for (
unsigned int i = 0; i < size; ++i) {
550 I_gray.bitmap[i] =
static_cast<unsigned char>((0.299 * rgb.
R) + (0.587 * rgb.
G) + (0.114 * rgb.
B));
554 I_gray.subsample(4, 4, I_4);
555 I_gray.subsample(8, 8, I_8);
557 const bool normalize =
true;
567 const float alpha = 0.5f;
569 float stdev =
static_cast<float>(I.
getStdev(p_mask));
574 else if (stdev <= 80) {
575 p = (-0.025f * stdev) + 3.f;
580 for (
unsigned int i = 0; i < size; ++i) {
581 bool hasToCompute =
true;
582 if (p_mask !=
nullptr) {
583 hasToCompute = p_mask->
bitmap[i];
587 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
588 float iNormalized =
static_cast<float>(I_gray.bitmap[i])/255.f;
589 float o = std::pow(iNormalized, gamma) * 255.f;
591 float e = std::pow(r, p);
592 float s = 255.f * std::pow(o / 255.f, e);
593 I.
bitmap[i].R = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].R)) / o);
594 I.
bitmap[i].G = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].G)) / o);
595 I.
bitmap[i].B = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].B)) / o);
603 float inverse_gamma = 1.0;
605 inverse_gamma = 1.0f / gamma;
607 unsigned char lut[256];
608 for (
unsigned int i = 0; i < 256; ++i) {
609 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.0, inverse_gamma) * 255.0);
615 std::stringstream errMsg;
616 errMsg <<
"ERROR: gamma correction factor (";
617 errMsg << gamma <<
") cannot be negative when using a constant user-defined factor." << std::endl;
620 else if (gamma > 0) {
621 std::stringstream errMsg;
622 errMsg <<
"ERROR: asking for automatic gamma correction but setting a user-defined factor (" << gamma <<
")." << std::endl;
627 gammaCorrectionNonLinearMethod(I, p_mask);
630 gammaCorrectionLogMethod(I, p_mask);
633 gammaCorrectionClassBasedMethod(I, p_mask);
636 gammaCorrectionProbBasedMethod(I, p_mask);
639 gammaCorrectionSpatialBased(I, p_mask);
642 std::stringstream errMsg;
643 errMsg <<
"Gamma automatic method \"" <<
vpGammaMethodToString(method) <<
"\" is not handled." << std::endl;
660 gammaCorrectionSpatialBased(I, p_mask);
665 unsigned int size = height * width;
666 std::vector<unsigned char> hue(size);
667 std::vector<unsigned char> saturation(size);
668 std::vector<unsigned char> value(size);
689 std::stringstream errMsg;
691 errMsg <<
"\" is not handled." << std::endl;
708 unsigned char min = 255, max = 0;
711 unsigned char range = max - min;
714 unsigned char lut[256];
716 for (
unsigned int x = min; x <= max; ++x) {
717 lut[x] = (255 * (x - min)) / range;
737 vpRGBa min = 255, max = 0;
747 unsigned char minChannel, maxChannel;
766 unsigned char rangeR = max.
R - min.
R;
768 for (
unsigned int x = min.
R; x <= max.R; ++x) {
769 lut[x].
R = (255 * (x - min.
R)) / rangeR;
773 lut[min.
R].
R = min.
R;
776 unsigned char rangeG = max.G - min.
G;
778 for (
unsigned int x = min.
G; x <= max.G; ++x) {
779 lut[x].
G = (255 * (x - min.
G)) / rangeG;
783 lut[min.
G].
G = min.
G;
786 unsigned char rangeB = max.B - min.
B;
788 for (
unsigned int x = min.
B; x <= max.B; ++x) {
789 lut[x].
B = (255 * (x - min.
B)) / rangeB;
793 lut[min.
B].
B = min.
B;
796 unsigned char rangeA = max.A - min.
A;
798 for (
unsigned int x = min.
A; x <= max.A; ++x) {
799 lut[x].
A = (255 * (x - min.
A)) / rangeA;
803 lut[min.
A].
A = min.
A;
827 double minSaturation, maxSaturation, minValue, maxValue;
828 saturationImage.getMinMaxValue(minSaturation, maxSaturation);
831 double *ptrStart = saturationImage.bitmap;
832 double *ptrEnd = saturationImage.bitmap + size;
833 double *ptrCurrent = ptrStart;
836 if ((maxSaturation - minSaturation) > 0.0) {
837 while (ptrCurrent != ptrEnd) {
838 *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
844 if ((maxValue - minValue) > 0.0) {
845 ptrStart = valueImage.
bitmap;
846 ptrEnd = valueImage.
bitmap + size;
847 ptrCurrent = ptrStart;
849 while (ptrCurrent != ptrEnd) {
850 *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
869 if ((weight < 1.0) && (weight >= 0.0)) {
870 #if defined(VISP_HAVE_SIMDLIB)
874 gaussian_filter.
apply(I, I_blurred);
878 unsigned int size = 7;
884 unsigned int i_size = I.
getSize();
885 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
886 double val = (I.
bitmap[cpt] - (weight * I_blurred.
bitmap[cpt])) / (1 - weight);
887 I.
bitmap[cpt] = vpMath::saturate<unsigned char>(val);
901 if ((weight < 1.0) && (weight >= 0.0)) {
902 #if defined(VISP_HAVE_SIMDLIB)
906 gaussian_filter.
apply(I, I_blurred);
911 unsigned int size = 7;
921 unsigned int i_size = I.
getSize();
922 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
923 #if defined(VISP_HAVE_SIMDLIB)
924 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred.
bitmap[cpt].
R)) / (1 - weight);
925 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred.
bitmap[cpt].
G)) / (1 - weight);
926 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred.
bitmap[cpt].
B)) / (1 - weight);
928 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred_R.
bitmap[cpt])) / (1 - weight);
929 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred_G.
bitmap[cpt])) / (1 - weight);
930 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred_B.
bitmap[cpt])) / (1 - weight);
932 I.
bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
933 I.
bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
934 I.
bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
void apply(const vpImage< unsigned char > &I, vpImage< unsigned char > &I_blur)
Class to compute a gray level image histogram.
unsigned int getTotal()
Get the total number of pixels in the input image.
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
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)
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, unsigned int size)
static void merge(const vpImage< unsigned char > *R, const vpImage< unsigned char > *G, const vpImage< unsigned char > *B, const vpImage< unsigned char > *a, vpImage< vpRGBa > &RGBa)
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=nullptr)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true, const vpImage< bool > *p_mask=nullptr)
void subsample(unsigned int v_scale, unsigned int h_scale, vpImage< Type > &sampled) const
unsigned int getWidth() const
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
unsigned int getSize() const
Type * bitmap
points toward the bitmap
double getStdev(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Return the standard deviation of the bitmap.
unsigned int getHeight() const
void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal=true) const
Look for the minimum and the maximum value within the bitmap.
double getMeanValue(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Return the mean value of the bitmap.
unsigned char B
Blue component.
unsigned char R
Red component.
unsigned char G
Green component.
unsigned char A
Additionnal component.
VISP_EXPORT void adjust(vpImage< unsigned char > &I, double alpha, double beta)
VISP_EXPORT void stretchContrast(vpImage< unsigned char > &I)
VISP_EXPORT void stretchContrastHSV(vpImage< vpRGBa > &I)
VISP_EXPORT void gammaCorrection(vpImage< unsigned char > &I, const float &gamma, const vpGammaMethod &method=vp::GAMMA_MANUAL, const vpImage< bool > *p_mask=nullptr)
VISP_EXPORT void equalizeHistogram(vpImage< unsigned char > &I, const vpImage< bool > *p_mask=nullptr)
VISP_EXPORT void unsharpMask(vpImage< unsigned char > &I, float sigma, double weight=0.6)
vpGammaMethod
Gamma Correction automatic methods.
@ GAMMA_SPATIAL_VARIANT_BASED
@ GAMMA_CLASSIFICATION_BASED
VISP_EXPORT vpGammaColorHandling vpGammaColorHandlingFromString(const std::string &name)
Cast a string into a vp::vpGammaColorHandling.
vpGammaColorHandling
How to handle color images when applying Gamma Correction.
@ GAMMA_COLOR_HANDLING_COUNT
VISP_EXPORT std::string vpGammaColorHandlingList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpGammaColorHandling.
VISP_EXPORT std::string vpGammaMethodList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpGammaMethod.
VISP_EXPORT std::string vpGammaColorHandlingToString(const vpGammaColorHandling &type)
Cast a vp::vpGammaColorHandling into a string, to know its name.
VISP_EXPORT vpGammaMethod vpGammaMethodFromString(const std::string &name)
Cast a string into a vp::vpGammaMethod.
VISP_EXPORT std::string vpGammaMethodToString(const vpGammaMethod &type)
Cast a vp::vpGammaMethod into a string, to know its name.