Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
vpImgproc.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Convert image types.
33  *
34  * Authors:
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 /* Autostretch HSV 0.10 --- image filter plug-in for GIMP
39  *
40  * Copyright (C) 1997 Scott Goehring
41  * Copyright (C) 1996 Federico Mena Quintero
42  *
43  * You can contact me at scott@poverty.bloomington.in.us
44  *
45  * This program is free software: you can redistribute it and/or modify
46  * it under the terms of the GNU General Public License as published by
47  * the Free Software Foundation; either version 3 of the License, or
48  * (at your option) any later version.
49  *
50  * This program is distributed in the hope that it will be useful,
51  * but WITHOUT ANY WARRANTY; without even the implied warranty of
52  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53  * GNU General Public License for more details.
54  *
55  * You should have received a copy of the GNU General Public License
56  * along with this program. If not, see <http://www.gnu.org/licenses/>.
57  */
58 
64 #include <visp3/core/vpHistogram.h>
65 #include <visp3/core/vpImageConvert.h>
66 #include <visp3/core/vpImageFilter.h>
67 #include <visp3/core/vpMath.h>
68 #include <visp3/core/vpGaussianFilter.h>
69 #include <visp3/imgproc/vpImgproc.h>
70 
81 void vp::adjust(vpImage<unsigned char> &I, double alpha, double beta)
82 {
83  // Construct the look-up table
84  unsigned char lut[256];
85  for (unsigned int i = 0; i < 256; i++) {
86  lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
87  }
88 
89  // Apply the transformation using a LUT
90  I.performLut(lut);
91 }
92 
104 void vp::adjust(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, double alpha, double beta)
105 {
106  // Copy I1 to I2
107  I2 = I1;
108 
109  vp::adjust(I2, alpha, beta);
110 }
111 
122 void vp::adjust(vpImage<vpRGBa> &I, double alpha, double beta)
123 {
124  // Construct the look-up table
125  vpRGBa lut[256];
126  for (unsigned int i = 0; i < 256; i++) {
127  lut[i].R = vpMath::saturate<unsigned char>(alpha * i + beta);
128  lut[i].G = vpMath::saturate<unsigned char>(alpha * i + beta);
129  lut[i].B = vpMath::saturate<unsigned char>(alpha * i + beta);
130  lut[i].A = vpMath::saturate<unsigned char>(alpha * i + beta);
131  }
132 
133  // Apply the transformation using a LUT
134  I.performLut(lut);
135 }
136 
148 void vp::adjust(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, double alpha, double beta)
149 {
150  // Copy I1 to I2
151  I2 = I1;
152 
153  vp::adjust(I2, alpha, beta);
154 }
155 
166 {
167  if (I.getWidth() * I.getHeight() == 0) {
168  return;
169  }
170 
171  // Calculate the histogram
172  vpHistogram hist;
173  hist.calculate(I);
174 
175  // Calculate the cumulative distribution function
176  unsigned int cdf[256];
177  unsigned int cdfMin = /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX, cdfMax = 0;
178  unsigned int minValue =
179  /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX,
180  maxValue = 0;
181  cdf[0] = hist[0];
182 
183  if (cdf[0] < cdfMin && cdf[0] > 0) {
184  cdfMin = cdf[0];
185  minValue = 0;
186  }
187 
188  for (unsigned int i = 1; i < 256; i++) {
189  cdf[i] = cdf[i - 1] + hist[i];
190 
191  if (cdf[i] < cdfMin && cdf[i] > 0) {
192  cdfMin = cdf[i];
193  minValue = i;
194  }
195 
196  if (cdf[i] > cdfMax) {
197  cdfMax = cdf[i];
198  maxValue = i;
199  }
200  }
201 
202  unsigned int nbPixels = I.getWidth() * I.getHeight();
203  if (nbPixels == cdfMin) {
204  // Only one brightness value in the image
205  return;
206  }
207 
208  // Construct the look-up table
209  unsigned char lut[256];
210  for (unsigned int x = minValue; x <= maxValue; x++) {
211  lut[x] = vpMath::round((cdf[x] - cdfMin) / (double)(nbPixels - cdfMin) * 255.0);
212  }
213 
214  I.performLut(lut);
215 }
216 
228 {
229  I2 = I1;
231 }
232 
247 {
248  if (I.getWidth() * I.getHeight() == 0) {
249  return;
250  }
251 
252  if (!useHSV) {
253  // Split the RGBa image into 4 images
258 
259  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
260 
261  // Apply histogram equalization for each channel
265 
266  // Merge the result in I
267  unsigned int size = I.getWidth() * I.getHeight();
268  unsigned char *ptrStart = (unsigned char *)I.bitmap;
269  unsigned char *ptrEnd = ptrStart + size * 4;
270  unsigned char *ptrCurrent = ptrStart;
271 
272  unsigned int cpt = 0;
273  while (ptrCurrent != ptrEnd) {
274  *ptrCurrent = pR.bitmap[cpt];
275  ++ptrCurrent;
276 
277  *ptrCurrent = pG.bitmap[cpt];
278  ++ptrCurrent;
279 
280  *ptrCurrent = pB.bitmap[cpt];
281  ++ptrCurrent;
282 
283  *ptrCurrent = pa.bitmap[cpt];
284  ++ptrCurrent;
285 
286  cpt++;
287  }
288  } else {
290  vpImage<unsigned char> saturation(I.getHeight(), I.getWidth());
291  vpImage<unsigned char> value(I.getHeight(), I.getWidth());
292 
293  unsigned int size = I.getWidth() * I.getHeight();
294  // Convert from RGBa to HSV
295  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, (unsigned char *)hue.bitmap,
296  (unsigned char *)saturation.bitmap, (unsigned char *)value.bitmap, size);
297 
298  // Histogram equalization on the value plane
299  vp::equalizeHistogram(value);
300 
301  // Convert from HSV to RGBa
302  vpImageConvert::HSVToRGBa((unsigned char *)hue.bitmap, (unsigned char *)saturation.bitmap,
303  (unsigned char *)value.bitmap, (unsigned char *)I.bitmap, size);
304  }
305 }
306 
321 void vp::equalizeHistogram(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, bool useHSV)
322 {
323  I2 = I1;
324  vp::equalizeHistogram(I2, useHSV);
325 }
326 
336 {
337  double inverse_gamma = 1.0;
338  if (gamma > 0) {
339  inverse_gamma = 1.0 / gamma;
340  } else {
341  throw vpException(vpException::badValue, "The gamma value must be positive !");
342  }
343 
344  // Construct the look-up table
345  unsigned char lut[256];
346  for (unsigned int i = 0; i < 256; i++) {
347  lut[i] = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
348  }
349 
350  I.performLut(lut);
351 }
352 
363 {
364  I2 = I1;
365  vp::gammaCorrection(I2, gamma);
366 }
367 
376 void vp::gammaCorrection(vpImage<vpRGBa> &I, double gamma)
377 {
378  double inverse_gamma = 1.0;
379  if (gamma > 0) {
380  inverse_gamma = 1.0 / gamma;
381  } else {
382  throw vpException(vpException::badValue, "The gamma value must be positive !");
383  }
384 
385  // Construct the look-up table
386  vpRGBa lut[256];
387  for (unsigned int i = 0; i < 256; i++) {
388  lut[i].R = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
389  lut[i].G = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
390  lut[i].B = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
391  lut[i].A = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
392  }
393 
394  I.performLut(lut);
395 }
396 
406 void vp::gammaCorrection(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, double gamma)
407 {
408  I2 = I1;
409  vp::gammaCorrection(I2, gamma);
410 }
411 
420 {
421  // Find min and max intensity values
422  unsigned char min = 255, max = 0;
423  I.getMinMaxValue(min, max);
424 
425  unsigned char range = max - min;
426 
427  // Construct the look-up table
428  unsigned char lut[256];
429  if (range > 0) {
430  for (unsigned int x = min; x <= max; x++) {
431  lut[x] = 255 * (x - min) / range;
432  }
433  } else {
434  lut[min] = min;
435  }
436 
437  I.performLut(lut);
438 }
439 
449 {
450  // Copy I1 to I2
451  I2 = I1;
453 }
454 
463 {
464  // Find min and max intensity values
465  vpRGBa min = 255, max = 0;
466 
467  // Split the RGBa image into 4 images
472 
473  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
474  // Min max values calculated for each channel
475  unsigned char minChannel, maxChannel;
476  pR.getMinMaxValue(minChannel, maxChannel);
477  min.R = minChannel;
478  max.R = maxChannel;
479 
480  pG.getMinMaxValue(minChannel, maxChannel);
481  min.G = minChannel;
482  max.G = maxChannel;
483 
484  pB.getMinMaxValue(minChannel, maxChannel);
485  min.B = minChannel;
486  max.B = maxChannel;
487 
488  pa.getMinMaxValue(minChannel, maxChannel);
489  min.A = minChannel;
490  max.A = maxChannel;
491 
492  // Construct the look-up table
493  vpRGBa lut[256];
494  unsigned char rangeR = max.R - min.R;
495  if (rangeR > 0) {
496  for (unsigned int x = min.R; x <= max.R; x++) {
497  lut[x].R = 255 * (x - min.R) / rangeR;
498  }
499  } else {
500  lut[min.R].R = min.R;
501  }
502 
503  unsigned char rangeG = max.G - min.G;
504  if (rangeG > 0) {
505  for (unsigned int x = min.G; x <= max.G; x++) {
506  lut[x].G = 255 * (x - min.G) / rangeG;
507  }
508  } else {
509  lut[min.G].G = min.G;
510  }
511 
512  unsigned char rangeB = max.B - min.B;
513  if (rangeB > 0) {
514  for (unsigned int x = min.B; x <= max.B; x++) {
515  lut[x].B = 255 * (x - min.B) / rangeB;
516  }
517  } else {
518  lut[min.B].B = min.B;
519  }
520 
521  unsigned char rangeA = max.A - min.A;
522  if (rangeA > 0) {
523  for (unsigned int x = min.A; x <= max.A; x++) {
524  lut[x].A = 255 * (x - min.A) / rangeA;
525  }
526  } else {
527  lut[min.A].A = min.A;
528  }
529 
530  I.performLut(lut);
531 }
532 
542 {
543  // Copy I1 to I2
544  I2 = I1;
546 }
547 
557 {
558  unsigned int size = I.getWidth() * I.getHeight();
559 
560  // Convert RGB to HSV
561  vpImage<double> hueImage(I.getHeight(), I.getWidth()), saturationImage(I.getHeight(), I.getWidth()),
562  valueImage(I.getHeight(), I.getWidth());
563  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap,
564  size);
565 
566  // Find min and max Saturation and Value
567  double minSaturation, maxSaturation, minValue, maxValue;
568  saturationImage.getMinMaxValue(minSaturation, maxSaturation);
569  valueImage.getMinMaxValue(minValue, maxValue);
570 
571  double *ptrStart = saturationImage.bitmap;
572  double *ptrEnd = saturationImage.bitmap + size;
573  double *ptrCurrent = ptrStart;
574 
575  // Stretch Saturation
576  if (maxSaturation - minSaturation > 0.0) {
577  while (ptrCurrent != ptrEnd) {
578  *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
579  ++ptrCurrent;
580  }
581  }
582 
583  // Stretch Value
584  if (maxValue - minValue > 0.0) {
585  ptrStart = valueImage.bitmap;
586  ptrEnd = valueImage.bitmap + size;
587  ptrCurrent = ptrStart;
588 
589  while (ptrCurrent != ptrEnd) {
590  *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
591  ++ptrCurrent;
592  }
593  }
594 
595  // Convert HSV to RGBa
596  vpImageConvert::HSVToRGBa(hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap, (unsigned char *)I.bitmap,
597  size);
598 }
599 
610 {
611  // Copy I1 to I2
612  I2 = I1;
614 }
615 
625 void vp::unsharpMask(vpImage<unsigned char> &I, float sigma, double weight)
626 {
627  if (weight < 1.0 && weight >= 0.0) {
628  // Gaussian blurred image
629  vpGaussianFilter gaussian_filter(I.getWidth(), I.getHeight(), sigma);
630  vpImage<unsigned char> I_blurred;
631  gaussian_filter.apply(I, I_blurred);
632 
633  // Unsharp mask
634  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
635  double val = (I.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
636  I.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
637  }
638  }
639 }
640 
652  double weight)
653 {
654  // Copy I1 to I2
655  I2 = I1;
656  vp::unsharpMask(I2, sigma, weight);
657 }
658 
668 void vp::unsharpMask(vpImage<vpRGBa> &I, float sigma, double weight)
669 {
670  if (weight < 1.0 && weight >= 0.0) {
671  // Gaussian blurred image
672  vpGaussianFilter gaussian_filter(I.getWidth(), I.getHeight(), sigma);
673  vpImage<vpRGBa> I_blurred;
674  gaussian_filter.apply(I, I_blurred);
675 
676  // Unsharp mask
677  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
678  double val_R = (I.bitmap[cpt].R - weight * I_blurred.bitmap[cpt].R) / (1 - weight);
679  double val_G = (I.bitmap[cpt].G - weight * I_blurred.bitmap[cpt].G) / (1 - weight);
680  double val_B = (I.bitmap[cpt].B - weight * I_blurred.bitmap[cpt].B) / (1 - weight);
681 
682  I.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
683  I.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
684  I.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
685  }
686  }
687 }
688 
699 void vp::unsharpMask(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, float sigma, double weight)
700 {
701  // Copy I1 to I2
702  I2 = I1;
703  vp::unsharpMask(I2, sigma, weight);
704 }
705 
706 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
707 
719 void vp::unsharpMask(vpImage<unsigned char> &I, unsigned int size, double weight)
720 {
721  if (weight < 1.0 && weight >= 0.0) {
722  // Gaussian blurred image
723  vpImage<double> I_blurred;
724  vpImageFilter::gaussianBlur(I, I_blurred, size);
725 
726  // Unsharp mask
727  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
728  double val = (I.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
729  I.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
730  }
731  }
732 }
733 
747 void vp::unsharpMask(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, unsigned int size,
748  double weight)
749 {
750  // Copy I1 to I2
751  I2 = I1;
752 #if 0
753  vp::unsharpMask(I2, size, weight);
754 #else
755  //To avoid:
756  //warning: ‘void vp::unsharpMask(vpImage<unsigned char>&, unsigned int, double)’ is deprecated [-Wdeprecated-declarations]
757  if (weight < 1.0 && weight >= 0.0) {
758  // Gaussian blurred image
759  vpImage<double> I_blurred;
760  vpImageFilter::gaussianBlur(I2, I_blurred, size);
761 
762  // Unsharp mask
763  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
764  double val = (I2.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
765  I2.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
766  }
767  }
768 #endif
769 }
770 
783 void vp::unsharpMask(vpImage<vpRGBa> &I, unsigned int size, double weight)
784 {
785  if (weight < 1.0 && weight >= 0.0) {
786  // Gaussian blurred image
787  vpImage<double> I_blurred_R, I_blurred_G, I_blurred_B;
788  vpImage<unsigned char> I_R, I_G, I_B;
789 
790  vpImageConvert::split(I, &I_R, &I_G, &I_B);
791  vpImageFilter::gaussianBlur(I_R, I_blurred_R, size);
792  vpImageFilter::gaussianBlur(I_G, I_blurred_G, size);
793  vpImageFilter::gaussianBlur(I_B, I_blurred_B, size);
794 
795  // Unsharp mask
796  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
797  double val_R = (I.bitmap[cpt].R - weight * I_blurred_R.bitmap[cpt]) / (1 - weight);
798  double val_G = (I.bitmap[cpt].G - weight * I_blurred_G.bitmap[cpt]) / (1 - weight);
799  double val_B = (I.bitmap[cpt].B - weight * I_blurred_B.bitmap[cpt]) / (1 - weight);
800 
801  I.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
802  I.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
803  I.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
804  }
805  }
806 }
807 
821 void vp::unsharpMask(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, unsigned int size, double weight)
822 {
823  // Copy I1 to I2
824  I2 = I1;
825 #if 0
826  vp::unsharpMask(I2, size, weight);
827 #else
828  //To avoid:
829  //warning: ‘void vp::unsharpMask(vpImage<vpRGBa>&, unsigned int, double)’ is deprecated [-Wdeprecated-declarations]
830  if (weight < 1.0 && weight >= 0.0) {
831  // Gaussian blurred image
832  vpImage<double> I_blurred_R, I_blurred_G, I_blurred_B;
833  vpImage<unsigned char> I_R, I_G, I_B;
834 
835  vpImageConvert::split(I2, &I_R, &I_G, &I_B);
836  vpImageFilter::gaussianBlur(I_R, I_blurred_R, size);
837  vpImageFilter::gaussianBlur(I_G, I_blurred_G, size);
838  vpImageFilter::gaussianBlur(I_B, I_blurred_B, size);
839 
840  // Unsharp mask
841  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
842  double val_R = (I2.bitmap[cpt].R - weight * I_blurred_R.bitmap[cpt]) / (1 - weight);
843  double val_G = (I2.bitmap[cpt].G - weight * I_blurred_G.bitmap[cpt]) / (1 - weight);
844  double val_B = (I2.bitmap[cpt].B - weight * I_blurred_B.bitmap[cpt]) / (1 - weight);
845 
846  I2.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
847  I2.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
848  I2.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
849  }
850  }
851 #endif
852 }
853 #endif // Deprecated
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:1679
unsigned char B
Blue component.
Definition: vpRGBa.h:150
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
error that can be emited by ViSP classes.
Definition: vpException.h:71
Class to compute a gray level image histogram.
Definition: vpHistogram.h:112
static void split(const vpImage< vpRGBa > &src, vpImage< unsigned char > *pR, vpImage< unsigned char > *pG, vpImage< unsigned char > *pB, vpImage< unsigned char > *pa=NULL)
unsigned char G
Green component.
Definition: vpRGBa.h:149
Definition: vpRGBa.h:66
VISP_EXPORT void stretchContrast(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:419
VISP_EXPORT void stretchContrastHSV(vpImage< vpRGBa > &I)
Definition: vpImgproc.cpp:556
VISP_EXPORT void adjust(vpImage< unsigned char > &I, double alpha, double beta)
Definition: vpImgproc.cpp:81
unsigned char A
Additionnal component.
Definition: vpRGBa.h:151
static void gaussianBlur(const vpImage< unsigned char > &I, vpImage< double > &GI, unsigned int size=7, double sigma=0., bool normalize=true)
Gaussian filter class.
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 int round(double x)
Definition: vpMath.h:247
unsigned int getHeight() const
Definition: vpImage.h:188
unsigned int getSize() const
Definition: vpImage.h:227
unsigned char R
Red component.
Definition: vpRGBa.h:148
VISP_EXPORT void equalizeHistogram(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:165
VISP_EXPORT void gammaCorrection(vpImage< unsigned char > &I, double gamma)
Definition: vpImgproc.cpp:335
vp_deprecated VISP_EXPORT void unsharpMask(vpImage< unsigned char > &I, unsigned int size=7, double weight=0.6)
Definition: vpImgproc.cpp:719
unsigned int getWidth() const
Definition: vpImage.h:246
void getMinMaxValue(Type &min, Type &max) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:938