Visual Servoing Platform version 3.5.0
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
81void 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
104void 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
122void 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
148void 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());
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
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
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
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
406void 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
625void 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
668void 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
699void 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
719void 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
747void 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
783void 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
821void 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
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
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:113
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< double > &GI, unsigned int size=7, double sigma=0., bool normalize=true)
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
void performLut(const Type(&lut)[256], unsigned int nbThreads=1)
Definition: vpImage.h:1679
unsigned int getSize() const
Definition: vpImage.h:227
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
unsigned int getHeight() const
Definition: vpImage.h:188
static int round(double x)
Definition: vpMath.h:247
Definition: vpRGBa.h:67
unsigned char B
Blue component.
Definition: vpRGBa.h:150
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned char G
Green component.
Definition: vpRGBa.h:149
unsigned char A
Additionnal component.
Definition: vpRGBa.h:151
VISP_EXPORT void adjust(vpImage< unsigned char > &I, double alpha, double beta)
Definition: vpImgproc.cpp:81
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 gammaCorrection(vpImage< unsigned char > &I, double gamma)
Definition: vpImgproc.cpp:335
VISP_EXPORT void equalizeHistogram(vpImage< unsigned char > &I)
Definition: vpImgproc.cpp:165
vp_deprecated VISP_EXPORT void unsharpMask(vpImage< unsigned char > &I, unsigned int size=7, double weight=0.6)
Definition: vpImgproc.cpp:719