Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
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/imgproc/vpImgproc.h>
69 
80 void vp::adjust(vpImage<unsigned char> &I, const double alpha, const double beta)
81 {
82  // Construct the look-up table
83  unsigned char lut[256];
84  for (unsigned int i = 0; i < 256; i++) {
85  lut[i] = vpMath::saturate<unsigned char>(alpha * i + beta);
86  }
87 
88  // Apply the transformation using a LUT
89  I.performLut(lut);
90 }
91 
103 void vp::adjust(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, const double alpha, const double beta)
104 {
105  // Copy I1 to I2
106  I2 = I1;
107 
108  vp::adjust(I2, alpha, beta);
109 }
110 
121 void vp::adjust(vpImage<vpRGBa> &I, const double alpha, const double beta)
122 {
123  // Construct the look-up table
124  vpRGBa lut[256];
125  for (unsigned int i = 0; i < 256; i++) {
126  lut[i].R = vpMath::saturate<unsigned char>(alpha * i + beta);
127  lut[i].G = vpMath::saturate<unsigned char>(alpha * i + beta);
128  lut[i].B = vpMath::saturate<unsigned char>(alpha * i + beta);
129  lut[i].A = vpMath::saturate<unsigned char>(alpha * i + beta);
130  }
131 
132  // Apply the transformation using a LUT
133  I.performLut(lut);
134 }
135 
147 void vp::adjust(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, const double alpha, const double beta)
148 {
149  // Copy I1 to I2
150  I2 = I1;
151 
152  vp::adjust(I2, alpha, beta);
153 }
154 
165 {
166  if (I.getWidth() * I.getHeight() == 0) {
167  return;
168  }
169 
170  // Calculate the histogram
171  vpHistogram hist;
172  hist.calculate(I);
173 
174  // Calculate the cumulative distribution function
175  unsigned int cdf[256];
176  unsigned int cdfMin = /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX, cdfMax = 0;
177  unsigned int minValue =
178  /*std::numeric_limits<unsigned int>::max()*/ UINT_MAX,
179  maxValue = 0;
180  cdf[0] = hist[0];
181 
182  if (cdf[0] < cdfMin && cdf[0] > 0) {
183  cdfMin = cdf[0];
184  minValue = 0;
185  }
186 
187  for (unsigned int i = 1; i < 256; i++) {
188  cdf[i] = cdf[i - 1] + hist[i];
189 
190  if (cdf[i] < cdfMin && cdf[i] > 0) {
191  cdfMin = cdf[i];
192  minValue = i;
193  }
194 
195  if (cdf[i] > cdfMax) {
196  cdfMax = cdf[i];
197  maxValue = i;
198  }
199  }
200 
201  unsigned int nbPixels = I.getWidth() * I.getHeight();
202  if (nbPixels == cdfMin) {
203  // Only one brightness value in the image
204  return;
205  }
206 
207  // Construct the look-up table
208  unsigned char lut[256];
209  for (unsigned int x = minValue; x <= maxValue; x++) {
210  lut[x] = vpMath::round((cdf[x] - cdfMin) / (double)(nbPixels - cdfMin) * 255.0);
211  }
212 
213  I.performLut(lut);
214 }
215 
227 {
228  I2 = I1;
230 }
231 
245 void vp::equalizeHistogram(vpImage<vpRGBa> &I, const bool useHSV)
246 {
247  if (I.getWidth() * I.getHeight() == 0) {
248  return;
249  }
250 
251  if (!useHSV) {
252  // Split the RGBa image into 4 images
257 
258  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
259 
260  // Apply histogram equalization for each channel
264 
265  // Merge the result in I
266  unsigned int size = I.getWidth() * I.getHeight();
267  unsigned char *ptrStart = (unsigned char *)I.bitmap;
268  unsigned char *ptrEnd = ptrStart + size * 4;
269  unsigned char *ptrCurrent = ptrStart;
270 
271  unsigned int cpt = 0;
272  while (ptrCurrent != ptrEnd) {
273  *ptrCurrent = pR.bitmap[cpt];
274  ++ptrCurrent;
275 
276  *ptrCurrent = pG.bitmap[cpt];
277  ++ptrCurrent;
278 
279  *ptrCurrent = pB.bitmap[cpt];
280  ++ptrCurrent;
281 
282  *ptrCurrent = pa.bitmap[cpt];
283  ++ptrCurrent;
284 
285  cpt++;
286  }
287  } else {
289  vpImage<unsigned char> saturation(I.getHeight(), I.getWidth());
290  vpImage<unsigned char> value(I.getHeight(), I.getWidth());
291 
292  unsigned int size = I.getWidth() * I.getHeight();
293  // Convert from RGBa to HSV
294  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, (unsigned char *)hue.bitmap,
295  (unsigned char *)saturation.bitmap, (unsigned char *)value.bitmap, size);
296 
297  // Histogram equalization on the value plane
298  vp::equalizeHistogram(value);
299 
300  // Convert from HSV to RGBa
301  vpImageConvert::HSVToRGBa((unsigned char *)hue.bitmap, (unsigned char *)saturation.bitmap,
302  (unsigned char *)value.bitmap, (unsigned char *)I.bitmap, size);
303  }
304 }
305 
320 void vp::equalizeHistogram(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, const bool useHSV)
321 {
322  I2 = I1;
323  vp::equalizeHistogram(I2, useHSV);
324 }
325 
334 void vp::gammaCorrection(vpImage<unsigned char> &I, const double gamma)
335 {
336  double inverse_gamma = 1.0;
337  if (gamma > 0) {
338  inverse_gamma = 1.0 / gamma;
339  } else {
340  throw vpException(vpException::badValue, "The gamma value must be positive !");
341  }
342 
343  // Construct the look-up table
344  unsigned char lut[256];
345  for (unsigned int i = 0; i < 256; i++) {
346  lut[i] = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
347  }
348 
349  I.performLut(lut);
350 }
351 
361 void vp::gammaCorrection(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, const double gamma)
362 {
363  I2 = I1;
364  vp::gammaCorrection(I2, gamma);
365 }
366 
375 void vp::gammaCorrection(vpImage<vpRGBa> &I, const double gamma)
376 {
377  double inverse_gamma = 1.0;
378  if (gamma > 0) {
379  inverse_gamma = 1.0 / gamma;
380  } else {
381  throw vpException(vpException::badValue, "The gamma value must be positive !");
382  }
383 
384  // Construct the look-up table
385  vpRGBa lut[256];
386  for (unsigned int i = 0; i < 256; i++) {
387  lut[i].R = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
388  lut[i].G = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
389  lut[i].B = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
390  lut[i].A = vpMath::saturate<unsigned char>(pow((double)i / 255.0, inverse_gamma) * 255.0);
391  }
392 
393  I.performLut(lut);
394 }
395 
405 void vp::gammaCorrection(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, const double gamma)
406 {
407  I2 = I1;
408  vp::gammaCorrection(I2, gamma);
409 }
410 
419 {
420  // Find min and max intensity values
421  unsigned char min = 255, max = 0;
422  I.getMinMaxValue(min, max);
423 
424  unsigned char range = max - min;
425 
426  // Construct the look-up table
427  unsigned char lut[256];
428  if (range > 0) {
429  for (unsigned int x = min; x <= max; x++) {
430  lut[x] = 255 * (x - min) / range;
431  }
432  } else {
433  lut[min] = min;
434  }
435 
436  I.performLut(lut);
437 }
438 
448 {
449  // Copy I1 to I2
450  I2 = I1;
452 }
453 
462 {
463  // Find min and max intensity values
464  vpRGBa min = 255, max = 0;
465 
466  // Split the RGBa image into 4 images
471 
472  vpImageConvert::split(I, &pR, &pG, &pB, &pa);
473  // Min max values calculated for each channel
474  unsigned char minChannel, maxChannel;
475  pR.getMinMaxValue(minChannel, maxChannel);
476  min.R = minChannel;
477  max.R = maxChannel;
478 
479  pG.getMinMaxValue(minChannel, maxChannel);
480  min.G = minChannel;
481  max.G = maxChannel;
482 
483  pB.getMinMaxValue(minChannel, maxChannel);
484  min.B = minChannel;
485  max.B = maxChannel;
486 
487  pa.getMinMaxValue(minChannel, maxChannel);
488  min.A = minChannel;
489  max.A = maxChannel;
490 
491  // Construct the look-up table
492  vpRGBa lut[256];
493  unsigned char rangeR = max.R - min.R;
494  if (rangeR > 0) {
495  for (unsigned int x = min.R; x <= max.R; x++) {
496  lut[x].R = 255 * (x - min.R) / rangeR;
497  }
498  } else {
499  lut[min.R].R = min.R;
500  }
501 
502  unsigned char rangeG = max.G - min.G;
503  if (rangeG > 0) {
504  for (unsigned int x = min.G; x <= max.G; x++) {
505  lut[x].G = 255 * (x - min.G) / rangeG;
506  }
507  } else {
508  lut[min.G].G = min.G;
509  }
510 
511  unsigned char rangeB = max.B - min.B;
512  if (rangeB > 0) {
513  for (unsigned int x = min.B; x <= max.B; x++) {
514  lut[x].B = 255 * (x - min.B) / rangeB;
515  }
516  } else {
517  lut[min.B].B = min.B;
518  }
519 
520  unsigned char rangeA = max.A - min.A;
521  if (rangeA > 0) {
522  for (unsigned int x = min.A; x <= max.A; x++) {
523  lut[x].A = 255 * (x - min.A) / rangeA;
524  }
525  } else {
526  lut[min.A].A = min.A;
527  }
528 
529  I.performLut(lut);
530 }
531 
541 {
542  // Copy I1 to I2
543  I2 = I1;
545 }
546 
556 {
557  unsigned int size = I.getWidth() * I.getHeight();
558 
559  // Convert RGB to HSV
560  vpImage<double> hueImage(I.getHeight(), I.getWidth()), saturationImage(I.getHeight(), I.getWidth()),
561  valueImage(I.getHeight(), I.getWidth());
562  vpImageConvert::RGBaToHSV((unsigned char *)I.bitmap, hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap,
563  size);
564 
565  // Find min and max Saturation and Value
566  double minSaturation, maxSaturation, minValue, maxValue;
567  saturationImage.getMinMaxValue(minSaturation, maxSaturation);
568  valueImage.getMinMaxValue(minValue, maxValue);
569 
570  double *ptrStart = saturationImage.bitmap;
571  double *ptrEnd = saturationImage.bitmap + size;
572  double *ptrCurrent = ptrStart;
573 
574  // Stretch Saturation
575  if (maxSaturation - minSaturation > 0.0) {
576  while (ptrCurrent != ptrEnd) {
577  *ptrCurrent = (*ptrCurrent - minSaturation) / (maxSaturation - minSaturation);
578  ++ptrCurrent;
579  }
580  }
581 
582  // Stretch Value
583  if (maxValue - minValue > 0.0) {
584  ptrStart = valueImage.bitmap;
585  ptrEnd = valueImage.bitmap + size;
586  ptrCurrent = ptrStart;
587 
588  while (ptrCurrent != ptrEnd) {
589  *ptrCurrent = (*ptrCurrent - minValue) / (maxValue - minValue);
590  ++ptrCurrent;
591  }
592  }
593 
594  // Convert HSV to RGBa
595  vpImageConvert::HSVToRGBa(hueImage.bitmap, saturationImage.bitmap, valueImage.bitmap, (unsigned char *)I.bitmap,
596  size);
597 }
598 
609 {
610  // Copy I1 to I2
611  I2 = I1;
613 }
614 
624 void vp::unsharpMask(vpImage<unsigned char> &I, const unsigned int size, const double weight)
625 {
626  if (weight < 1.0 && weight >= 0.0) {
627  // Gaussian blurred image
628  vpImage<double> I_blurred;
629  vpImageFilter::gaussianBlur(I, I_blurred, size);
630 
631  // Unsharp mask
632  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
633  double val = (I.bitmap[cpt] - weight * I_blurred.bitmap[cpt]) / (1 - weight);
634  I.bitmap[cpt] = vpMath::saturate<unsigned char>(val); // val > 255 ? 255 : (val < 0 ? 0 : val);
635  }
636  }
637 }
638 
649 void vp::unsharpMask(const vpImage<unsigned char> &I1, vpImage<unsigned char> &I2, const unsigned int size,
650  const double weight)
651 {
652  // Copy I1 to I2
653  I2 = I1;
654  vp::unsharpMask(I2, size, weight);
655 }
656 
666 void vp::unsharpMask(vpImage<vpRGBa> &I, const unsigned int size, const double weight)
667 {
668  if (weight < 1.0 && weight >= 0.0) {
669  // Gaussian blurred image
670  vpImage<double> I_blurred_R, I_blurred_G, I_blurred_B;
671  vpImage<unsigned char> I_R, I_G, I_B;
672 
673  vpImageConvert::split(I, &I_R, &I_G, &I_B);
674  vpImageFilter::gaussianBlur(I_R, I_blurred_R, size);
675  vpImageFilter::gaussianBlur(I_G, I_blurred_G, size);
676  vpImageFilter::gaussianBlur(I_B, I_blurred_B, size);
677 
678  // Unsharp mask
679  for (unsigned int cpt = 0; cpt < I.getSize(); cpt++) {
680  double val_R = (I.bitmap[cpt].R - weight * I_blurred_R.bitmap[cpt]) / (1 - weight);
681  double val_G = (I.bitmap[cpt].G - weight * I_blurred_G.bitmap[cpt]) / (1 - weight);
682  double val_B = (I.bitmap[cpt].B - weight * I_blurred_B.bitmap[cpt]) / (1 - weight);
683 
684  I.bitmap[cpt].R = vpMath::saturate<unsigned char>(val_R);
685  I.bitmap[cpt].G = vpMath::saturate<unsigned char>(val_G);
686  I.bitmap[cpt].B = vpMath::saturate<unsigned char>(val_B);
687  }
688  }
689 }
690 
701 void vp::unsharpMask(const vpImage<vpRGBa> &I1, vpImage<vpRGBa> &I2, const unsigned int size, const double weight)
702 {
703  // Copy I1 to I2
704  I2 = I1;
705  vp::unsharpMask(I2, size, weight);
706 }
VISP_EXPORT void unsharpMask(vpImage< unsigned char > &I, const unsigned int size=7, const double weight=0.6)
Definition: vpImgproc.cpp:624
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
unsigned int getWidth() const
Definition: vpImage.h:239
void getMinMaxValue(Type &min, Type &max) const
Look for the minimum and the maximum value within the bitmap.
Definition: vpImage.h:1000
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Type * bitmap
points toward the bitmap
Definition: vpImage.h:133
VISP_EXPORT void adjust(vpImage< unsigned char > &I, const double alpha, const double beta)
Definition: vpImgproc.cpp:80
error that can be emited by ViSP classes.
Definition: vpException.h:71
Class to compute a gray level image histogram.
Definition: vpHistogram.h:112
VISP_EXPORT void gammaCorrection(vpImage< unsigned char > &I, const double gamma)
Definition: vpImgproc.cpp:334
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
static int round(const double x)
Definition: vpMath.h:235
Definition: vpRGBa.h:66
VISP_EXPORT void stretchContrast(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:418
VISP_EXPORT void stretchContrastHSV(vpImage< vpRGBa > &I)
Definition: vpImgproc.cpp:555
unsigned int getSize() const
Definition: vpImage.h:219
void calculate(const vpImage< unsigned char > &I, const unsigned int nbins=256, const unsigned int nbThreads=1)
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)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, const unsigned int size)
unsigned char R
Red component.
Definition: vpRGBa.h:148
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, const unsigned int size)
VISP_EXPORT void equalizeHistogram(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:164
unsigned int getHeight() const
Definition: vpImage.h:178
void performLut(const Type(&lut)[256], const unsigned int nbThreads=1)
Definition: vpImage.h:1800