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)));
332 float inverse_gamma = 1.f / gamma_computed;
335 unsigned char lut[256];
336 float inputRangeAsFloat =
static_cast<float>(inputRange);
337 for (
unsigned int i = inputMin; i <= inputMax; ++i) {
338 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i - inputMin) / inputRangeAsFloat, inverse_gamma) * 255.f);
358 const float a = 0.2f;
359 const float b = 0.3f;
360 const float c = 0.3f;
361 const float x_m = 127.5f;
362 const float alpha = std::atan2(-b, x_m);
363 const float rho = 0.1f;
364 const unsigned int lutSize = 256;
365 unsigned char lut[lutSize];
366 for (
unsigned int i = 0; i < lutSize; ++i) {
367 float x =
static_cast<float>(i);
368 float phi = (M_PI_FLOAT * x) / (2.f * x_m);
369 float f1 = a * std::cos(phi);
370 float k = rho * std::sin((4 * M_PI_FLOAT * x) / 255.f);
371 float f2 = ((k + b)*std::cos(alpha)) + (x * std::sin(alpha));
372 float r = c * std::abs((x / x_m) - 1.f);
373 float f3 = r * std::cos((3.f * M_PI_FLOAT * x) / 255.f);
374 float g = f1 + f2 + f3;
376 float inverse_gamma = 1.f / gamma;
377 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.f, inverse_gamma) * 255.f);
398 double meanNormalized = mean / 255.;
399 double stdevNormalized = stdev / 255.;
400 const float tau = 3.f;
401 bool isAlreadyHighContrast = (4. * stdevNormalized) > (1./tau);
402 const unsigned int lutSize = 256;
403 unsigned char lut[lutSize];
405 if (isAlreadyHighContrast) {
407 gamma =
static_cast<float>(std::exp((1.f - (meanNormalized + stdevNormalized))/2.f));
411 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
412 gamma = -
static_cast<float>(std::log2(stdevNormalized));
414 gamma = -
static_cast<float>(std::log(stdevNormalized) / std::log(2.f));
417 if (meanNormalized < 0.5) {
419 float meanPowerGamma =
static_cast<float>(std::pow(meanNormalized, gamma));
420 for (
unsigned int i = 0; i < lutSize; ++i) {
421 float iNormalized =
static_cast<float>(i)/255.f;
422 float iPowerGamma = std::pow(iNormalized, gamma);
423 lut[i] = vpMath::saturate<unsigned char>(255.f * (iPowerGamma / (iPowerGamma + ((1.f - iPowerGamma) * meanPowerGamma))));
428 for (
unsigned int i = 0; i < lutSize; ++i) {
429 float iNormalized =
static_cast<float>(i)/255.f;
430 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
450 const unsigned int nbBins = 256;
454 unsigned int totalNbPoints = histo.
getTotal();
455 unsigned int minHisto = histo[0];
456 unsigned int maxHisto = histo[0];
457 for (
unsigned int i = 1; i < nbBins; ++i) {
458 minHisto = std::min(minHisto, histo[i]);
459 maxHisto = std::max(maxHisto, histo[i]);
461 float pdfMin =
static_cast<float>(minHisto) /
static_cast<float>(totalNbPoints);
462 float pdfMax =
static_cast<float>(maxHisto) /
static_cast<float>(totalNbPoints);
464 float sum_pdf_w = 0.f;
465 for (
unsigned int i = 0; i < nbBins; ++i) {
466 float pdf =
static_cast<float>(histo[i])/
static_cast<float>(totalNbPoints);
467 pdf_w[i] = pdfMax * std::sqrt((pdf - pdfMin)/(pdfMax - pdfMin));
468 sum_pdf_w += pdf_w[i];
470 unsigned char lut[nbBins];
472 for (
unsigned int i = 0; i < nbBins; ++i) {
473 cdf_w += pdf_w[i] / sum_pdf_w;
474 float gamma = 1.f - cdf_w;
475 float iNormalized =
static_cast<float>(i)/255.f;
476 lut[i] = vpMath::saturate<unsigned char>(std::pow(iNormalized, gamma) * 255.f);
493 const unsigned int scale2 = 2, scale4 = 4, scale8 = 8;
499 const bool normalize =
true;
500 const unsigned int gaussKernelSize = 3;
510 const float alpha = 0.5f;
511 unsigned int size = height * width;
512 float stdev =
static_cast<float>(I.
getStdev(p_mask));
514 const float stdevThresh1 = 40., stdevThresh2 = 80.;
515 if (stdev <= stdevThresh1) {
518 else if (stdev <= stdevThresh2) {
519 p = (-0.025f * stdev) + 3.f;
525 for (
unsigned int i = 0; i < size; ++i) {
526 bool hasToCompute =
true;
527 if (p_mask !=
nullptr) {
528 hasToCompute = p_mask->
bitmap[i];
532 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
533 float iNormalized =
static_cast<float>(I.
bitmap[i])/255.f;
534 float o = std::pow(iNormalized, gamma) * 255.f;
536 float e = std::pow(r, p);
537 float s = 255.f * std::pow(o / 255.f, e);
538 I.
bitmap[i] = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i])) / o);
555 unsigned int size = height * width;
557 for (
unsigned int i = 0; i < size; ++i) {
559 I_gray.
bitmap[i] =
static_cast<unsigned char>((0.299 * rgb.
R) + (0.587 * rgb.
G) + (0.114 * rgb.
B));
562 const unsigned int scale2 = 2, scale4 = 4, scale8 = 8;
567 const bool normalize =
true;
568 const unsigned int gaussKernelSize = 3;
578 const float alpha = 0.5f;
580 float stdev =
static_cast<float>(I.
getStdev(p_mask));
582 const float stdevThresh1 = 40., stdevThresh2 = 80.;
583 if (stdev <= stdevThresh1) {
586 else if (stdev <= stdevThresh2) {
587 p = (-0.025f * stdev) + 3.f;
592 for (
unsigned int i = 0; i < size; ++i) {
593 bool hasToCompute =
true;
594 if (p_mask !=
nullptr) {
595 hasToCompute = p_mask->
bitmap[i];
599 float gamma = std::pow(alpha, (128.f - svlm)/128.f);
600 float iNormalized =
static_cast<float>(I_gray.
bitmap[i])/255.f;
601 float o = std::pow(iNormalized, gamma) * 255.f;
603 float e = std::pow(r, p);
604 float s = 255.f * std::pow(o / 255.f, e);
605 I.
bitmap[i].R = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].R)) / o);
606 I.
bitmap[i].G = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].G)) / o);
607 I.
bitmap[i].B = vpMath::saturate<unsigned char>((s *
static_cast<float>(I.
bitmap[i].B)) / o);
614 float inverse_gamma = 1.0;
616 inverse_gamma = 1.0f / gamma;
618 const unsigned int lutSize = 256;
619 unsigned char lut[lutSize];
620 for (
unsigned int i = 0; i < lutSize; ++i) {
621 lut[i] = vpMath::saturate<unsigned char>(std::pow(
static_cast<float>(i) / 255.0, inverse_gamma) * 255.0);
627 std::stringstream errMsg;
628 errMsg <<
"ERROR: gamma correction factor (";
629 errMsg << gamma <<
") cannot be negative when using a constant user-defined factor." << std::endl;
632 else if (gamma > 0) {
633 std::stringstream errMsg;
634 errMsg <<
"ERROR: asking for automatic gamma correction but setting a user-defined factor (" << gamma <<
")." << std::endl;
654 std::stringstream errMsg;
655 errMsg <<
"Gamma automatic method \"" <<
vpGammaMethodToString(method) <<
"\" is not handled." << std::endl;
677 unsigned int size = height * width;
678 std::vector<unsigned char> hue(size);
679 std::vector<unsigned char> saturation(size);
680 std::vector<unsigned char> value(size);
701 std::stringstream errMsg;
703 errMsg <<
"\" is not handled." << std::endl;
720 unsigned char min = 255, max = 0;
723 unsigned char range = max - min;
726 const unsigned int lutSize = 256, maxVal = lutSize - 1;
727 unsigned char lut[lutSize];
729 for (
unsigned int x = min; x <= max; ++x) {
730 lut[x] = (maxVal * (x - min)) / range;
760 unsigned char minChannel, maxChannel;
778 const unsigned int lutSize = 256, maxVal = lutSize - 1;
780 unsigned char rangeR = max.
R - min.R;
782 for (
unsigned int x = min.R; x <= max.
R; ++x) {
783 lut[x].
R = (maxVal * (x - min.R)) / rangeR;
787 lut[min.R].
R = min.R;
790 unsigned char rangeG = max.
G - min.G;
792 for (
unsigned int x = min.G; x <= max.
G; ++x) {
793 lut[x].
G = (maxVal * (x - min.G)) / rangeG;
797 lut[min.G].
G = min.G;
800 unsigned char rangeB = max.
B - min.B;
802 for (
unsigned int x = min.B; x <= max.
B; ++x) {
803 lut[x].
B = (maxVal * (x - min.B)) / rangeB;
807 lut[min.B].
B = min.B;
810 unsigned char rangeA = max.
A - min.A;
812 for (
unsigned int x = min.A; x <= max.
A; ++x) {
813 lut[x].
A = (maxVal * (x - min.A)) / rangeA;
817 lut[min.A].
A = min.A;
841 double minSaturation, maxSaturation, minValue, maxValue;
842 saturationImage.getMinMaxValue(minSaturation, maxSaturation);
845 double *ptrStart = saturationImage.bitmap;
846 double *ptrEnd = saturationImage.bitmap + size;
847 double *ptrCurrent = ptrStart;
850 if ((maxSaturation - minSaturation) > 0.0) {
851 while (ptrCurrent != ptrEnd) {
852 *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
858 if ((maxValue - minValue) > 0.0) {
859 ptrStart = valueImage.
bitmap;
860 ptrEnd = valueImage.
bitmap + size;
861 ptrCurrent = ptrStart;
863 while (ptrCurrent != ptrEnd) {
864 *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
883 if ((weight < 1.0) && (weight >= 0.0)) {
884 #if defined(VISP_HAVE_SIMDLIB)
888 gaussian_filter.
apply(I, I_blurred);
892 unsigned int size = 7;
898 unsigned int i_size = I.
getSize();
899 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
900 double val = (I.
bitmap[cpt] - (weight * I_blurred.
bitmap[cpt])) / (1 - weight);
901 I.
bitmap[cpt] = vpMath::saturate<unsigned char>(val);
915 if ((weight < 1.0) && (weight >= 0.0)) {
916 #if defined(VISP_HAVE_SIMDLIB)
920 gaussian_filter.
apply(I, I_blurred);
925 unsigned int size = 7;
935 unsigned int i_size = I.
getSize();
936 for (
unsigned int cpt = 0; cpt < i_size; ++cpt) {
937 #if defined(VISP_HAVE_SIMDLIB)
938 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred.
bitmap[cpt].
R)) / (1 - weight);
939 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred.
bitmap[cpt].
G)) / (1 - weight);
940 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred.
bitmap[cpt].
B)) / (1 - weight);
942 double val_R = (I.
bitmap[cpt].R - (weight * I_blurred_R.
bitmap[cpt])) / (1 - weight);
943 double val_G = (I.
bitmap[cpt].G - (weight * I_blurred_G.
bitmap[cpt])) / (1 - weight);
944 double val_B = (I.
bitmap[cpt].B - (weight * I_blurred_B.
bitmap[cpt])) / (1 - weight);
946 I.
bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
947 I.
bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
948 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.