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 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) && defined(ENABLE_VISP_NAMESPACE)
73 std::string
vpGammaMethodList(
const std::string &pref,
const std::string &sep,
const std::string &suf)
75 std::string list(pref);
92 name =
"gamma_manual";
98 name =
"gamma_nonlinear";
104 name =
"gamma_classification";
107 name =
"gamma_spatial_variant";
111 name =
"gamma_method_unknown";
120 bool notFound =
true;
122 while ((i < count) && notFound) {
135 std::string list(pref);
152 name =
"gamma_color_rgb";
155 name =
"gamma_color_hsv";
159 name =
"gamma_color_unknown";
168 bool notFound =
true;
170 while ((i < count) && notFound) {
184 const unsigned int lutSize = 256;
185 unsigned char lut[lutSize];
186 for (
unsigned int i = 0; i < lutSize; ++i) {
187 lut[i] = vpMath::saturate<unsigned char>((alpha * i) + beta);
205 const unsigned int lutSize = 256;
207 for (
unsigned int i = 0; i < lutSize; ++i) {
208 lut[i].
R = vpMath::saturate<unsigned char>((alpha * i) + beta);
209 lut[i].
G = vpMath::saturate<unsigned char>((alpha * i) + beta);
210 lut[i].
B = vpMath::saturate<unsigned char>((alpha * i) + beta);
211 lut[i].
A = vpMath::saturate<unsigned char>((alpha * i) + beta);
267 unsigned char *ptrStart =
reinterpret_cast<unsigned char *
>(I.
bitmap);
268 unsigned char *ptrEnd = ptrStart + (size * 4);
269 unsigned char *ptrCurrent = ptrStart;
271 unsigned int cpt = 0;
272 while (ptrCurrent != ptrEnd) {
273 *ptrCurrent = pR.
bitmap[cpt];
276 *ptrCurrent = pG.
bitmap[cpt];
279 *ptrCurrent = pB.
bitmap[cpt];
282 *ptrCurrent = pa.
bitmap[cpt];
296 reinterpret_cast<unsigned char *
>(saturation.
bitmap),
reinterpret_cast<unsigned char *
>(value.
bitmap), size);
303 reinterpret_cast<unsigned char *
>(value.
bitmap),
reinterpret_cast<unsigned char *
>(I.
bitmap), size);
326 float mean =
static_cast<float>(I.
getMeanValue(p_mask));
327 unsigned char inputMin = 0, inputMax = 0;
329 unsigned char inputRange = inputMax - inputMin;
331 float gamma_computed =
static_cast<float>((std::log(128.f) - std::log(256.f)) / (std::log(mean) - std::log(inputRange)));
334 unsigned char lut[256];
335 float inputRangeAsFloat =
static_cast<float>(inputRange);
336 for (
unsigned int i = inputMin; i <= inputMax; ++i) {
337 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i - inputMin) / inputRangeAsFloat, gamma_computed) * 255.f);
357 const float a = 0.2f;
358 const float b = 0.3f;
359 const float c = 0.3f;
360 const float x_m = 127.5f;
361 const float alpha = std::atan2(-b, x_m);
362 const float rho = 0.1f;
363 const unsigned int lutSize = 256;
364 unsigned char lut[lutSize];
365 for (
unsigned int i = 0; i < lutSize; ++i) {
366 float x =
static_cast<float>(i);
367 float phi = (M_PI_FLOAT * x) / (2.f * x_m);
368 float f1 = a * std::cos(phi);
369 float k = rho * std::sin((4 * M_PI_FLOAT * x) / 255.f);
370 float f2 = ((k + b)*std::cos(alpha)) + (x * std::sin(alpha));
371 float r = c * std::abs((x / x_m) - 1.f);
372 float f3 = r * std::cos((3.f * M_PI_FLOAT * x) / 255.f);
373 float g = f1 + f2 + f3;
375 float inverse_gamma = 1.f / gamma;
376 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.f, inverse_gamma) * 255.f);
397 double meanNormalized = mean / 255.;
398 double stdevNormalized = stdev / 255.;
399 const float tau = 3.f;
400 bool isAlreadyHighContrast = (4. * stdevNormalized) > (1./tau);
401 const unsigned int lutSize = 256;
402 unsigned char lut[lutSize];
404 if (isAlreadyHighContrast) {
406 gamma =
static_cast<float>(std::exp((1.f - (meanNormalized + stdevNormalized))/2.f));
410 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
411 gamma = -
static_cast<float>(std::log2(stdevNormalized));
413 gamma = -
static_cast<float>(std::log(stdevNormalized) / std::log(2.f));
416 if (meanNormalized < 0.5) {
418 float meanPowerGamma =
static_cast<float>(std::pow(meanNormalized, gamma));
419 for (
unsigned int i = 0; i < lutSize; ++i) {
420 float iNormalized =
static_cast<float>(i)/255.f;
421 float iPowerGamma = std::pow(iNormalized, gamma);
422 lut[i] = vpMath::saturate<unsigned char>(255.f * (iPowerGamma / (iPowerGamma + ((1.f - iPowerGamma) * meanPowerGamma))));
427 for (
unsigned int i = 0; i < lutSize; ++i) {
428 float iNormalized =
static_cast<float>(i)/255.f;
429 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
449 const unsigned int nbBins = 256;
453 unsigned int totalNbPoints = histo.
getTotal();
454 unsigned int minHisto = histo[0];
455 unsigned int maxHisto = histo[0];
456 for (
unsigned int i = 1; i < nbBins; ++i) {
457 minHisto = std::min(minHisto, histo[i]);
458 maxHisto = std::max(maxHisto, histo[i]);
460 float pdfMin =
static_cast<float>(minHisto) /
static_cast<float>(totalNbPoints);
461 float pdfMax =
static_cast<float>(maxHisto) /
static_cast<float>(totalNbPoints);
463 float sum_pdf_w = 0.f;
464 for (
unsigned int i = 0; i < nbBins; ++i) {
465 float pdf =
static_cast<float>(histo[i])/
static_cast<float>(totalNbPoints);
466 pdf_w[i] = pdfMax * std::sqrt((pdf - pdfMin)/(pdfMax - pdfMin));
467 sum_pdf_w += pdf_w[i];
469 unsigned char lut[nbBins];
471 for (
unsigned int i = 0; i < nbBins; ++i) {
472 cdf_w += pdf_w[i] / sum_pdf_w;
473 float gamma = 1.f - cdf_w;
474 float iNormalized =
static_cast<float>(i)/255.f;
475 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
492 const unsigned int scale2 = 2, scale4 = 4, scale8 = 8;
498 const bool normalize =
true;
499 const unsigned int gaussKernelSize = 3;
509 const float alpha = 0.5f;
510 unsigned int size = height * width;
511 float stdev =
static_cast<float>(I.
getStdev(p_mask));
513 const float stdevThresh1 = 40., stdevThresh2 = 80.;
514 if (stdev <= stdevThresh1) {
517 else if (stdev <= stdevThresh2) {
518 p = (-0.025f * stdev) + 3.f;
524 for (
unsigned int i = 0; i < size; ++i) {
525 bool hasToCompute =
true;
526 if (p_mask !=
nullptr) {
527 hasToCompute = p_mask->
bitmap[i];
531 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
532 float iNormalized =
static_cast<float>(I.
bitmap[i])/255.f;
533 float o = std::pow(iNormalized, gamma) * 255.f;
535 float e = std::pow(r, p);
536 float s = 255.f * std::pow(o / 255.f, e);
537 I.
bitmap[i] = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i])) / o);
554 unsigned int size = height * width;
556 for (
unsigned int i = 0; i < size; ++i) {
558 I_gray.
bitmap[i] =
static_cast<unsigned char>((0.299 * rgb.
R) + (0.587 * rgb.
G) + (0.114 * rgb.
B));
561 const unsigned int scale2 = 2, scale4 = 4, scale8 = 8;
566 const bool normalize =
true;
567 const unsigned int gaussKernelSize = 3;
577 const float alpha = 0.5f;
579 float stdev =
static_cast<float>(I.
getStdev(p_mask));
581 const float stdevThresh1 = 40., stdevThresh2 = 80.;
582 if (stdev <= stdevThresh1) {
585 else if (stdev <= stdevThresh2) {
586 p = (-0.025f * stdev) + 3.f;
591 for (
unsigned int i = 0; i < size; ++i) {
592 bool hasToCompute =
true;
593 if (p_mask !=
nullptr) {
594 hasToCompute = p_mask->
bitmap[i];
598 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
599 float iNormalized =
static_cast<float>(I_gray.
bitmap[i])/255.f;
600 float o = std::pow(iNormalized, gamma) * 255.f;
602 float e = std::pow(r, p);
603 float s = 255.f * std::pow(o / 255.f, e);
604 I.
bitmap[i].R = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].R)) / o);
605 I.
bitmap[i].G = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].G)) / o);
606 I.
bitmap[i].B = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].B)) / o);
613 float inverse_gamma = 1.0;
615 inverse_gamma = 1.0f / gamma;
617 const unsigned int lutSize = 256;
618 unsigned char lut[lutSize];
619 for (
unsigned int i = 0; i < lutSize; ++i) {
620 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.0, inverse_gamma) * 255.0);
626 std::stringstream errMsg;
627 errMsg <<
"ERROR: gamma correction factor (";
628 errMsg << gamma <<
") cannot be negative when using a constant user-defined factor." << std::endl;
631 else if (gamma > 0) {
632 std::stringstream errMsg;
633 errMsg <<
"ERROR: asking for automatic gamma correction but setting a user-defined factor (" << gamma <<
")." << std::endl;
653 std::stringstream errMsg;
654 errMsg <<
"Gamma automatic method \"" <<
vpGammaMethodToString(method) <<
"\" is not handled." << std::endl;
676 unsigned int size = height * width;
677 std::vector<unsigned char> hue(size);
678 std::vector<unsigned char> saturation(size);
679 std::vector<unsigned char> value(size);
700 std::stringstream errMsg;
702 errMsg <<
"\" is not handled." << std::endl;
719 unsigned char min = 255, max = 0;
722 unsigned char range = max - min;
725 const unsigned int lutSize = 256, maxVal = lutSize - 1;
726 unsigned char lut[lutSize];
728 for (
unsigned int x = min; x <= max; ++x) {
729 lut[x] = (maxVal * (x - min)) / range;
759 unsigned char minChannel, maxChannel;
777 const unsigned int lutSize = 256, maxVal = lutSize - 1;
779 unsigned char rangeR = max.
R - min.R;
781 for (
unsigned int x = min.R; x <= max.
R; ++x) {
782 lut[x].
R = (maxVal * (x - min.R)) / rangeR;
786 lut[min.R].
R = min.R;
789 unsigned char rangeG = max.
G - min.G;
791 for (
unsigned int x = min.G; x <= max.
G; ++x) {
792 lut[x].
G = (maxVal * (x - min.G)) / rangeG;
796 lut[min.G].
G = min.G;
799 unsigned char rangeB = max.
B - min.B;
801 for (
unsigned int x = min.B; x <= max.
B; ++x) {
802 lut[x].
B = (maxVal * (x - min.B)) / rangeB;
806 lut[min.B].
B = min.B;
809 unsigned char rangeA = max.
A - min.A;
811 for (
unsigned int x = min.A; x <= max.
A; ++x) {
812 lut[x].
A = (maxVal * (x - min.A)) / rangeA;
816 lut[min.A].
A = min.A;
840 double minSaturation, maxSaturation, minValue, maxValue;
841 saturationImage.getMinMaxValue(minSaturation, maxSaturation);
844 double *ptrStart = saturationImage.bitmap;
845 double *ptrEnd = saturationImage.bitmap + size;
846 double *ptrCurrent = ptrStart;
849 if ((maxSaturation - minSaturation) > 0.0) {
850 while (ptrCurrent != ptrEnd) {
851 *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
857 if ((maxValue - minValue) > 0.0) {
858 ptrStart = valueImage.
bitmap;
859 ptrEnd = valueImage.
bitmap + size;
860 ptrCurrent = ptrStart;
862 while (ptrCurrent != ptrEnd) {
863 *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
882 if ((weight < 1.0) && (weight >= 0.0)) {
883 #if defined(VISP_HAVE_SIMDLIB)
887 gaussian_filter.
apply(I, I_blurred);
891 unsigned int size = 7;
897 unsigned int i_size = I.
getSize();
898 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
899 double val = (I.
bitmap[cpt] - (weight * I_blurred.
bitmap[cpt])) / (1 - weight);
900 I.
bitmap[cpt] = vpMath::saturate<unsigned char>(val);
914 if ((weight < 1.0) && (weight >= 0.0)) {
915 #if defined(VISP_HAVE_SIMDLIB)
919 gaussian_filter.
apply(I, I_blurred);
924 unsigned int size = 7;
934 unsigned int i_size = I.
getSize();
935 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
936 #if defined(VISP_HAVE_SIMDLIB)
937 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred.
bitmap[cpt].
R)) / (1 - weight);
938 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred.
bitmap[cpt].
G)) / (1 - weight);
939 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred.
bitmap[cpt].
B)) / (1 - weight);
941 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred_R.
bitmap[cpt])) / (1 - weight);
942 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred_G.
bitmap[cpt])) / (1 - weight);
943 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred_B.
bitmap[cpt])) / (1 - weight);
945 I.
bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
946 I.
bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
947 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(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, double alpha, double beta)
VISP_EXPORT void stretchContrast(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I)
VISP_EXPORT void stretchContrastHSV(VISP_NAMESPACE_ADDRESSING vpImage< VISP_NAMESPACE_ADDRESSING vpRGBa > &I)
VISP_EXPORT void gammaCorrection(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, const float &gamma, const vpGammaMethod &method=GAMMA_MANUAL, const VISP_NAMESPACE_ADDRESSING vpImage< bool > *p_mask=nullptr)
VISP_EXPORT void equalizeHistogram(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, const VISP_NAMESPACE_ADDRESSING vpImage< bool > *p_mask=nullptr)
VISP_EXPORT void unsharpMask(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, float sigma, double weight=0.6)
VISP_EXPORT vpGammaMethod vpGammaMethodFromString(const std::string &name)
Cast a string into a vpGammaMethod.
void gammaCorrectionClassBasedMethod(vpImage< unsigned char > &I, const vpImage< bool > *p_mask)
This method is an implementation of the article "An adaptive gamma correction for image enhancement",...
void gammaCorrectionNonLinearMethod(vpImage< unsigned char > &I, const vpImage< bool > *p_mask)
This method is an implementation of the article "REDUCING ILLUMINATION BASED ON NONLINEAR GAMMA CORRE...
VISP_EXPORT vpGammaColorHandling vpGammaColorHandlingFromString(const std::string &name)
Cast a string into a vpGammaColorHandling.
vpGammaColorHandling
How to handle color images when applying Gamma Correction.
@ GAMMA_COLOR_HANDLING_COUNT
VISP_EXPORT std::string vpGammaColorHandlingToString(const vpGammaColorHandling &type)
Cast a vpGammaColorHandling into a string, to know its name.
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 vpGammaColorHandlingList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpGammaColorHandling.
void gammaCorrectionSpatialBased(vpImage< unsigned char > &I, const vpImage< bool > *p_mask)
This technique comes from the article "A Space-Variant Luminance Map based Color Image Enhancement" b...
void gammaCorrectionProbBasedMethod(vpImage< unsigned char > &I, const vpImage< bool > *p_mask)
This technique comes from the article "Efficient Contrast Enhancement Using Adaptive Gamma Correction...
vpGammaMethod
Gamma Correction automatic methods.
@ GAMMA_CLASSIFICATION_BASED
@ GAMMA_SPATIAL_VARIANT_BASED
void gammaCorrectionLogMethod(vpImage< unsigned char > &I, const vpImage< bool > *p_mask)
This method is an implementation of the article "Towards Real-time Hardware Gamma Correction for Dyna...
VISP_EXPORT std::string vpGammaMethodToString(const vpGammaMethod &type)
Cast a vpGammaMethod into a string, to know its name.