Visual Servoing Platform  version 3.5.1 under development (2023-09-22)
vpImgproc.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Convert image types.
32  */
33 /* Autostretch HSV 0.10 --- image filter plug-in for GIMP
34  *
35  * Copyright (C) 1997 Scott Goehring
36  * Copyright (C) 1996 Federico Mena Quintero
37  *
38  * You can contact me at scott@poverty.bloomington.in.us
39  *
40  * This program is free software: you can redistribute it and/or modify
41  * it under the terms of the GNU General Public License as published by
42  * the Free Software Foundation; either version 3 of the License, or
43  * (at your option) any later version.
44  *
45  * This program is distributed in the hope that it will be useful,
46  * but WITHOUT ANY WARRANTY; without even the implied warranty of
47  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48  * GNU General Public License for more details.
49  *
50  * You should have received a copy of the GNU General Public License
51  * along with this program. If not, see <http://www.gnu.org/licenses/>.
52 */
53 
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/vpMath.h>
64 #include <visp3/imgproc/vpImgproc.h>
65 
66 namespace vp
67 {
68 void adjust(vpImage<unsigned char> &I, double alpha, double beta)
69 {
70  // Construct the look-up table
71  unsigned char lut[256];
72  for (unsigned int i = 0; i < 256; i++) {
73  lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
74  }
75 
76  // Apply the transformation using a LUT
77  I.performLut(lut);
78 }
79 
80 void adjust(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, double alpha, double beta)
81 {
82  // Copy I1 to I2
83  I2 = I1;
84 
85  vp::adjust(I2, alpha, beta);
86 }
87 
88 void adjust(vpImage<vpRGBa> &I, double alpha, double beta)
89 {
90  // Construct the look-up table
91  vpRGBa lut[256];
92  for (unsigned int i = 0; i < 256; i++) {
93  lut[i].R = vpMath::saturate<unsigned char>(alpha * i + beta);
94  lut[i].G = vpMath::saturate<unsigned char>(alpha * i + beta);
95  lut[i].B = vpMath::saturate<unsigned char>(alpha * i + beta);
96  lut[i].A = vpMath::saturate<unsigned char>(alpha * i + beta);
97  }
98 
99  // Apply the transformation using a LUT
100  I.performLut(lut);
101 }
102 
103 void adjust(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, double alpha, double beta)
104 {
105  // Copy I1 to I2
106  I2 = I1;
107 
108  vp::adjust(I2, alpha, beta);
109 }
110 
112 {
113  if (I.getWidth() * I.getHeight() == 0) {
114  return;
115  }
116 
117  // Calculate the histogram
118  vpHistogram hist;
119  hist.calculate(I);
120 
121  // Calculate the cumulative distribution function
122  unsigned int cdf[256];
123  unsigned int cdfMin = /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX, cdfMax = 0;
124  unsigned int minValue =
125  /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX,
126  maxValue = 0;
127  cdf[0] = hist[0];
128 
129  if (cdf[0] < cdfMin && cdf[0] > 0) {
130  cdfMin = cdf[0];
131  minValue = 0;
132  }
133 
134  for (unsigned int i = 1; i < 256; i++) {
135  cdf[i] = cdf[i - 1] + hist[i];
136 
137  if (cdf[i] < cdfMin && cdf[i] > 0) {
138  cdfMin = cdf[i];
139  minValue = i;
140  }
141 
142  if (cdf[i] > cdfMax) {
143  cdfMax = cdf[i];
144  maxValue = i;
145  }
146  }
147 
148  unsigned int nbPixels = I.getWidth() * I.getHeight();
149  if (nbPixels == cdfMin) {
150  // Only one brightness value in the image
151  return;
152  }
153 
154  // Construct the look-up table
155  unsigned char lut[256];
156  for (unsigned int x = minValue; x <= maxValue; x++) {
157  lut[x] = vpMath::round((cdf[x] - cdfMin) / (double)(nbPixels - cdfMin) * 255.0);
158  }
159 
160  I.performLut(lut);
161 }
162 
164 {
165  I2 = I1;
167 }
168 
169 void equalizeHistogram(vpImage<vpRGBa> &I, bool useHSV)
170 {
171  if (I.getWidth() * I.getHeight() == 0) {
172  return;
173  }
174 
175  if (!useHSV) {
176  // Split the RGBa image into 4 images
181 
182  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
183 
184  // Apply histogram equalization for each channel
188 
189  // Merge the result in I
190  unsigned int size = I.getWidth() * I.getHeight();
191  unsigned char *ptrStart = (unsigned char *)I.bitmap;
192  unsigned char *ptrEnd = ptrStart + size * 4;
193  unsigned char *ptrCurrent = ptrStart;
194 
195  unsigned int cpt = 0;
196  while (ptrCurrent != ptrEnd) {
197  *ptrCurrent = pR.bitmap[cpt];
198  ++ptrCurrent;
199 
200  *ptrCurrent = pG.bitmap[cpt];
201  ++ptrCurrent;
202 
203  *ptrCurrent = pB.bitmap[cpt];
204  ++ptrCurrent;
205 
206  *ptrCurrent = pa.bitmap[cpt];
207  ++ptrCurrent;
208 
209  cpt++;
210  }
211  }
212  else {
214  vpImage<unsigned char> saturation(I.getHeight(), I.getWidth());
215  vpImage<unsigned char> value(I.getHeight(), I.getWidth());
216 
217  unsigned int size = I.getWidth() * I.getHeight();
218  // Convert from RGBa to HSV
219  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, (unsigned char *)hue.bitmap,
220  (unsigned char *)saturation.bitmap, (unsigned char *)value.bitmap, size);
221 
222  // Histogram equalization on the value plane
223  vp::equalizeHistogram(value);
224 
225  // Convert from HSV to RGBa
226  vpImageConvert::HSVToRGBa((unsigned char *)hue.bitmap, (unsigned char *)saturation.bitmap,
227  (unsigned char *)value.bitmap, (unsigned char *)I.bitmap, size);
228  }
229 }
230 
231 void equalizeHistogram(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, bool useHSV)
232 {
233  I2 = I1;
234  vp::equalizeHistogram(I2, useHSV);
235 }
236 
238 {
239  double inverse_gamma = 1.0;
240  if (gamma > 0) {
241  inverse_gamma = 1.0 / gamma;
242  }
243  else {
244  throw vpException(vpException::badValue, "The gamma value must be positive !");
245  }
246 
247  // Construct the look-up table
248  unsigned char lut[256];
249  for (unsigned int i = 0; i < 256; i++) {
250  lut[i] = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
251  }
252 
253  I.performLut(lut);
254 }
255 
257 {
258  I2 = I1;
259  vp::gammaCorrection(I2, gamma);
260 }
261 
262 void gammaCorrection(vpImage<vpRGBa> &I, double gamma)
263 {
264  double inverse_gamma = 1.0;
265  if (gamma > 0) {
266  inverse_gamma = 1.0 / gamma;
267  }
268  else {
269  throw vpException(vpException::badValue, "The gamma value must be positive !");
270  }
271 
272  // Construct the look-up table
273  vpRGBa lut[256];
274  for (unsigned int i = 0; i < 256; i++) {
275  lut[i].R = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
276  lut[i].G = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
277  lut[i].B = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
278  lut[i].A = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
279  }
280 
281  I.performLut(lut);
282 }
283 
284 void gammaCorrection(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, double gamma)
285 {
286  I2 = I1;
287  vp::gammaCorrection(I2, gamma);
288 }
289 
291 {
292  // Find min and max intensity values
293  unsigned char min = 255, max = 0;
294  I.getMinMaxValue(min, max);
295 
296  unsigned char range = max - min;
297 
298  // Construct the look-up table
299  unsigned char lut[256];
300  if (range > 0) {
301  for (unsigned int x = min; x <= max; x++) {
302  lut[x] = 255 * (x - min) / range;
303  }
304  }
305  else {
306  lut[min] = min;
307  }
308 
309  I.performLut(lut);
310 }
311 
313 {
314  // Copy I1 to I2
315  I2 = I1;
317 }
318 
320 {
321  // Find min and max intensity values
322  vpRGBa min = 255, max = 0;
323 
324  // Split the RGBa image into 4 images
329 
330  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
331  // Min max values calculated for each channel
332  unsigned char minChannel, maxChannel;
333  pR.getMinMaxValue(minChannel, maxChannel);
334  min.R = minChannel;
335  max.R = maxChannel;
336 
337  pG.getMinMaxValue(minChannel, maxChannel);
338  min.G = minChannel;
339  max.G = maxChannel;
340 
341  pB.getMinMaxValue(minChannel, maxChannel);
342  min.B = minChannel;
343  max.B = maxChannel;
344 
345  pa.getMinMaxValue(minChannel, maxChannel);
346  min.A = minChannel;
347  max.A = maxChannel;
348 
349  // Construct the look-up table
350  vpRGBa lut[256];
351  unsigned char rangeR = max.R - min.R;
352  if (rangeR > 0) {
353  for (unsigned int x = min.R; x <= max.R; x++) {
354  lut[x].R = 255 * (x - min.R) / rangeR;
355  }
356  }
357  else {
358  lut[min.R].R = min.R;
359  }
360 
361  unsigned char rangeG = max.G - min.G;
362  if (rangeG > 0) {
363  for (unsigned int x = min.G; x <= max.G; x++) {
364  lut[x].G = 255 * (x - min.G) / rangeG;
365  }
366  }
367  else {
368  lut[min.G].G = min.G;
369  }
370 
371  unsigned char rangeB = max.B - min.B;
372  if (rangeB > 0) {
373  for (unsigned int x = min.B; x <= max.B; x++) {
374  lut[x].B = 255 * (x - min.B) / rangeB;
375  }
376  }
377  else {
378  lut[min.B].B = min.B;
379  }
380 
381  unsigned char rangeA = max.A - min.A;
382  if (rangeA > 0) {
383  for (unsigned int x = min.A; x <= max.A; x++) {
384  lut[x].A = 255 * (x - min.A) / rangeA;
385  }
386  }
387  else {
388  lut[min.A].A = min.A;
389  }
390 
391  I.performLut(lut);
392 }
393 
395 {
396  // Copy I1 to I2
397  I2 = I1;
399 }
400 
402 {
403  unsigned int size = I.getWidth() * I.getHeight();
404 
405  // Convert RGB to HSV
406  vpImage<double> hueImage(I.getHeight(), I.getWidth()), saturationImage(I.getHeight(), I.getWidth()),
407  valueImage(I.getHeight(), I.getWidth());
408  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap,
409  size);
410 
411  // Find min and max Saturation and Value
412  double minSaturation, maxSaturation, minValue, maxValue;
413  saturationImage.getMinMaxValue(minSaturation, maxSaturation);
414  valueImage.getMinMaxValue(minValue, maxValue);
415 
416  double *ptrStart = saturationImage.bitmap;
417  double *ptrEnd = saturationImage.bitmap + size;
418  double *ptrCurrent = ptrStart;
419 
420  // Stretch Saturation
421  if (maxSaturation - minSaturation > 0.0) {
422  while (ptrCurrent != ptrEnd) {
423  *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
424  ++ptrCurrent;
425  }
426  }
427 
428  // Stretch Value
429  if (maxValue - minValue > 0.0) {
430  ptrStart = valueImage.bitmap;
431  ptrEnd = valueImage.bitmap + size;
432  ptrCurrent = ptrStart;
433 
434  while (ptrCurrent != ptrEnd) {
435  *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
436  ++ptrCurrent;
437  }
438  }
439 
440  // Convert HSV to RGBa
441  vpImageConvert::HSVToRGBa(hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap, (unsigned char *)I.bitmap,
442  size);
443 }
444 
446 {
447  // Copy I1 to I2
448  I2 = I1;
450 }
451 
452 void unsharpMask(vpImage<unsigned char> &I, float sigma, double weight)
453 {
454  if (weight < 1.0 && weight >= 0.0) {
455  // Gaussian blurred image
456  vpGaussianFilter gaussian_filter(I.getWidth(), I.getHeight(), sigma);
457  vpImage<unsigned char> I_blurred;
458  gaussian_filter.apply(I, I_blurred);
459 
460  // Unsharp mask
461  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
462  double val = (I.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
463  I.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
464  }
465  }
466 }
467 
468 void unsharpMask(const vpImage<unsigned char> &I, vpImage<unsigned char> &Ires, float sigma, double weight)
469 {
470  // Copy I to Ires
471  Ires = I;
472  vp::unsharpMask(Ires, sigma, weight);
473 }
474 
475 void unsharpMask(vpImage<vpRGBa> &I, float sigma, double weight)
476 {
477  if (weight < 1.0 && weight >= 0.0) {
478  // Gaussian blurred image
479  vpGaussianFilter gaussian_filter(I.getWidth(), I.getHeight(), sigma);
480  vpImage<vpRGBa> I_blurred;
481  gaussian_filter.apply(I, I_blurred);
482 
483  // Unsharp mask
484  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
485  double val_R = (I.bitmap[cpt].R - weight * I_blurred.bitmap[cpt].R) / (1 - weight);
486  double val_G = (I.bitmap[cpt].G - weight * I_blurred.bitmap[cpt].G) / (1 - weight);
487  double val_B = (I.bitmap[cpt].B - weight * I_blurred.bitmap[cpt].B) / (1 - weight);
488 
489  I.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
490  I.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
491  I.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
492  }
493  }
494 }
495 
496 void unsharpMask(const vpImage<vpRGBa> &I, vpImage<vpRGBa> &Ires, float sigma, double weight)
497 {
498  // Copy I to Ires
499  Ires = I;
500  vp::unsharpMask(Ires, sigma, weight);
501 }
502 
503 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
516 void unsharpMask(vpImage<unsigned char> &I, unsigned int size, double weight)
517 {
518  if (weight < 1.0 && weight >= 0.0) {
519  // Gaussian blurred image
520  vpImage<double> I_blurred;
521  vpImageFilter::gaussianBlur(I, I_blurred, size);
522 
523  // Unsharp mask
524  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
525  double val = (I.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
526  I.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
527  }
528  }
529 }
530 
544 void unsharpMask(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, unsigned int size, double weight)
545 {
546  // Copy I1 to I2
547  I2 = I1;
548 #if 0
549  vp::unsharpMask(I2, size, weight);
550 #else
551  // To avoid:
552  // warning: ‘void vp::unsharpMask(vpImage<unsigned char>&, unsigned int, double)’ is deprecated
553  // [-Wdeprecated-declarations]
554  if (weight < 1.0 && weight >= 0.0) {
555  // Gaussian blurred image
556  vpImage<double> I_blurred;
557  vpImageFilter::gaussianBlur(I2, I_blurred, size);
558 
559  // Unsharp mask
560  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
561  double val = (I2.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
562  I2.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
563  }
564  }
565 #endif
566 }
567 
580 void unsharpMask(vpImage<vpRGBa> &I, unsigned int size, double weight)
581 {
582  if (weight < 1.0 && weight >= 0.0) {
583  // Gaussian blurred image
584  vpImage<double> I_blurred_R, I_blurred_G, I_blurred_B;
585  vpImage<unsigned char> I_R, I_G, I_B;
586 
587  vpImageConvert::split(I, &I_R, &I_G, &I_B);
588  vpImageFilter::gaussianBlur(I_R, I_blurred_R, size);
589  vpImageFilter::gaussianBlur(I_G, I_blurred_G, size);
590  vpImageFilter::gaussianBlur(I_B, I_blurred_B, size);
591 
592  // Unsharp mask
593  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
594  double val_R = (I.bitmap[cpt].R - weight * I_blurred_R.bitmap[cpt]) / (1 - weight);
595  double val_G = (I.bitmap[cpt].G - weight * I_blurred_G.bitmap[cpt]) / (1 - weight);
596  double val_B = (I.bitmap[cpt].B - weight * I_blurred_B.bitmap[cpt]) / (1 - weight);
597 
598  I.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
599  I.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
600  I.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
601  }
602  }
603 }
604 
618 void unsharpMask(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, unsigned int size, double weight)
619 {
620  // Copy I1 to I2
621  I2 = I1;
622 #if 0
623  vp::unsharpMask(I2, size, weight);
624 #else
625  // To avoid:
626  // warning: ‘void vp::unsharpMask(vpImage<vpRGBa>&, unsigned int, double)’ is deprecated [-Wdeprecated-declarations]
627  if (weight < 1.0 && weight >= 0.0) {
628  // Gaussian blurred image
629  vpImage<double> I_blurred_R, I_blurred_G, I_blurred_B;
630  vpImage<unsigned char> I_R, I_G, I_B;
631 
632  vpImageConvert::split(I2, &I_R, &I_G, &I_B);
633  vpImageFilter::gaussianBlur(I_R, I_blurred_R, size);
634  vpImageFilter::gaussianBlur(I_G, I_blurred_G, size);
635  vpImageFilter::gaussianBlur(I_B, I_blurred_B, size);
636 
637  // Unsharp mask
638  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
639  double val_R = (I2.bitmap[cpt].R - weight * I_blurred_R.bitmap[cpt]) / (1 - weight);
640  double val_G = (I2.bitmap[cpt].G - weight * I_blurred_G.bitmap[cpt]) / (1 - weight);
641  double val_B = (I2.bitmap[cpt].B - weight * I_blurred_B.bitmap[cpt]) / (1 - weight);
642 
643  I2.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
644  I2.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
645  I2.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
646  }
647  }
648 #endif
649 }
650 #endif // Deprecated
651 };
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:85
Gaussian filter class.
void apply(const vpImage< unsigned char > &I, vpImage< unsigned char > &I_blur)
Class to compute a gray level image histogram.
Definition: vpHistogram.h:108
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, unsigned int size)
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=NULL)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static void gaussianBlur(const vpImage< unsigned char > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true)
unsigned int getWidth() const
Definition: vpImage.h:242
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:2017
unsigned int getSize() const
Definition: vpImage.h:223
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
void getMinMaxValue(Type &min, Type &max, bool onlyFiniteVal=true) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:1054
static int round(double x)
Definition: vpMath.h:323
Definition: vpRGBa.h:61
unsigned char B
Blue component.
Definition: vpRGBa.h:140
unsigned char R
Red component.
Definition: vpRGBa.h:138
unsigned char G
Green component.
Definition: vpRGBa.h:139
unsigned char A
Additionnal component.
Definition: vpRGBa.h:141
VISP_EXPORT void adjust(vpImage< unsigned char > &I, double alpha, double beta)
Definition: vpImgproc.cpp:68
VISP_EXPORT void stretchContrast(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:290
VISP_EXPORT void stretchContrastHSV(vpImage< vpRGBa > &I)
Definition: vpImgproc.cpp:401
VISP_EXPORT void gammaCorrection(vpImage< unsigned char > &I, double gamma)
Definition: vpImgproc.cpp:237
VISP_EXPORT void equalizeHistogram(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:111
vp_deprecated VISP_EXPORT void unsharpMask(vpImage< unsigned char > &I, unsigned int size=7, double weight=0.6)
Definition: vpImgproc.cpp:516