Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
tutorial-brightness-adjustment.cpp
1 
3 #include <cstdlib>
4 #include <iostream>
5 #include <visp3/core/vpConfig.h>
6 #include <visp3/core/vpImage.h>
7 #include <visp3/core/vpIoTools.h>
8 #include <visp3/gui/vpDisplayFactory.h>
9 #include <visp3/io/vpImageIo.h>
10 
11 #if defined(VISP_HAVE_MODULE_IMGPROC)
13 #include <visp3/imgproc/vpImgproc.h>
15 #endif
16 
17 #if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
18 #include <memory>
19 #endif
20 
21 #ifdef ENABLE_VISP_NAMESPACE
22 using namespace VISP_NAMESPACE_NAME;
23 #endif
24 
25 #if defined(VISP_HAVE_MODULE_IMGPROC) && defined(VISP_HAVE_DISPLAY) && \
26  (defined(VISP_HAVE_PNG) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_STBIMAGE) || defined(VISP_HAVE_SIMDLIB)) && \
27  ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
28 namespace
29 {
30 void display(vpImage<vpRGBa> &I_display, vpImage<vpRGBa> &I_color_res, const vpImage<vpRGBa> &I_color_adjust,
31  vpImage<unsigned char> &I_gray_res, vpImage<unsigned char> &I_gray_adjust, vpImage<vpRGBa> &I_gray_display,
32  const std::string &title, const std::string &filename_color, const std::string &filename_gray,
33  const std::string &title_2 = "")
34 {
35  I_color_res.insert(I_color_adjust, vpImagePoint(0, I_color_adjust.getWidth()));
36  I_display.insert(I_color_adjust, vpImagePoint(0, I_color_adjust.getWidth()));
37 
38  I_gray_res.insert(I_gray_adjust, vpImagePoint(0, I_gray_adjust.getWidth()));
39  vpImageConvert::convert(I_gray_adjust, I_gray_display);
40  I_display.insert(I_gray_display, vpImagePoint(I_color_adjust.getHeight(), I_color_adjust.getWidth()));
41 
42  vpImageIo::write(I_color_res, filename_color);
43  vpImageIo::write(I_gray_res, filename_gray);
44 
45  vpDisplay::display(I_display);
46  vpDisplay::displayText(I_display, 20, 20, title, vpColor::red);
47  if (!title_2.empty()) {
48  vpDisplay::displayText(I_display, 40, static_cast<unsigned int>(I_color_adjust.getWidth()*0.85),
49  title_2, vpColor::green);
50  }
51  vpDisplay::flush(I_display);
52  vpDisplay::getClick(I_display);
53 }
54 }
55 #endif
56 
57 int main(int argc, const char **argv)
58 {
60 #if defined(VISP_HAVE_MODULE_IMGPROC) && defined(VISP_HAVE_DISPLAY) && \
61  (defined(VISP_HAVE_PNG) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_STBIMAGE) || defined(VISP_HAVE_SIMDLIB)) && \
62  ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
64 
65  std::string input_filename = "Sample_low_brightness.png";
66  double alpha = 10.0, beta = 50.0;
67  double gamma = 3.5;
70  int scale = 240, scaleDiv = 3, level = 0, kernelSize = -1;
71  double dynamic = 3.0;
72  int scale_display = 2;
73 
74  for (int i = 1; i < argc; i++) {
75  if (std::string(argv[i]) == "--input" && i + 1 < argc) {
76  ++i;
77  input_filename = std::string(argv[i]);
78  }
79  else if (std::string(argv[i]) == "--alpha" && i + 1 < argc) {
80  ++i;
81  alpha = atof(argv[i]);
82  }
83  else if (std::string(argv[i]) == "--beta" && i + 1 < argc) {
84  ++i;
85  beta = atof(argv[i]);
86  }
87  else if (std::string(argv[i]) == "--gamma" && i + 1 < argc) {
88  ++i;
89  gamma = atof(argv[i]);
90  }
91  else if ((std::string(argv[i]) == "--gamma-color-handling") && ((i + 1) < argc)) {
92  ++i;
94  }
95  else if ((std::string(argv[i]) == "--gamma-method") && ((i + 1) < argc)) {
96  ++i;
98  }
99  else if (std::string(argv[i]) == "--scale" && i + 1 < argc) {
100  ++i;
101  scale = atoi(argv[i]);
102  }
103  else if (std::string(argv[i]) == "--scaleDiv" && i + 1 < argc) {
104  ++i;
105  scaleDiv = atoi(argv[i]);
106  }
107  else if (std::string(argv[i]) == "--level" && i + 1 < argc) {
108  ++i;
109  level = atoi(argv[i]);
110  }
111  else if (std::string(argv[i]) == "--kernelSize" && i + 1 < argc) {
112  ++i;
113  kernelSize = atoi(argv[i]);
114  }
115  else if (std::string(argv[i]) == "--dynamic" && i + 1 < argc) {
116  ++i;
117  dynamic = atof(argv[i]);
118  }
119  else if (std::string(argv[i]) == "--scale-display" && i + 1 < argc) {
120  ++i;
121  scale_display = atoi(argv[i]);
122  }
123  else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
124  std::cout << "Usage: " << argv[0]
125  << " [--input <input image>]"
126  " [--alpha <alpha for adjust()>] [--beta <beta for adjust()>]"
127  " [--gamma <gamma for gammaCorrection()>]"
128  " [--gamma-color-handling " << VISP_NAMESPACE_NAME::vpGammaColorHandlingList() << "]"
129  " [--gamma-method " << VISP_NAMESPACE_NAME::vpGammaMethodList() << "]"
130  " [--scale <scale for retinex()> [--scaleDiv for retinex()]"
131  " [--level <level for retinex()> [--kernelSize <kernelSize for retinex()>]"
132  " [--dynamic <dynamic for retinex()>] "
133  " [--scale-display <display downscaling factor>] "
134  " [--help]"
135  << std::endl;
136  return EXIT_SUCCESS;
137  }
138  }
139 
140  // Filename without extension to save the results
141  const std::string input_name = vpIoTools::getNameWE(input_filename);
142 
143  vpImage<vpRGBa> I_color;
144  vpImageIo::read(I_color, input_filename);
145  vpImage<unsigned char> I_gray;
146  vpImageConvert::convert(I_color, I_gray);
147  vpImage<vpRGBa> I_gray_display;
148  vpImageConvert::convert(I_gray, I_gray_display);
149 
150  // Side-by-side images
151  vpImage<vpRGBa> I_color_res(I_color.getHeight(), 2 * I_color.getWidth());
152  I_color_res.insert(I_color, vpImagePoint());
153  vpImage<unsigned char> I_gray_res(I_gray.getHeight(), 2 * I_gray.getWidth());
154  I_gray_res.insert(I_gray, vpImagePoint());
155 
156  // Side-by-side display for color (top) and gray (bottom) images
157  vpImage<vpRGBa> I_display(2 * I_color.getHeight(), 2 * I_color.getWidth());
158  I_display.insert(I_color, vpImagePoint());
159  I_display.insert(I_gray_display, vpImagePoint(I_color.getHeight(), 0));
160  std::shared_ptr<vpDisplay> d = vpDisplayFactory::createDisplay();
161  d->setDownScalingFactor(static_cast<vpDisplay::vpScaleType>(scale_display));
162  d->init(I_display, 10, 10, "Brightness adjustment results");
163 
165  vpImage<vpRGBa> I_color_adjust;
166  VISP_NAMESPACE_NAME::adjust(I_color, I_color_adjust, alpha, beta);
167  vpImage<unsigned char> I_gray_adjust;
168  VISP_NAMESPACE_NAME::adjust(I_gray, I_gray_adjust, alpha, beta);
170 
171  std::stringstream ss_color;
172  ss_color << input_name << "_adjust_alpha=" << alpha << "_beta=" << beta << ".png";
173  std::stringstream ss_gray;
174  ss_gray << input_name << "_adjust_alpha=" << alpha << "_beta=" << beta << "_gray.png";
175  display(I_display, I_color_res, I_color_adjust, I_gray_res, I_gray_adjust, I_gray_display,
176  "Brightness and contrast adjustment. Click to continue.", ss_color.str(), ss_gray.str());
177 
179  if (method != VISP_NAMESPACE_NAME::GAMMA_MANUAL) {
180  // If the user wants to use an automatic method, the gamma factor must be negative.
181  gamma = -1.;
182  }
183 
184  if (gamma > 0.) {
185  // If the user wants to set a constant user-defined gamma factor, the method must be set to manual.
187  }
188  vpImage<vpRGBa> I_color_gamma_correction;
189  VISP_NAMESPACE_NAME::gammaCorrection(I_color, I_color_gamma_correction, static_cast<float>(gamma), colorHandling, method);
190  vpImage<unsigned char> I_gray_gamma_correction;
191  VISP_NAMESPACE_NAME::gammaCorrection(I_gray, I_gray_gamma_correction, static_cast<float>(gamma), method);
193 
194  ss_color.str("");
195  ss_color << input_name << "_gamma=" << gamma << ".png";
196  ss_gray.str("");
197  ss_gray << input_name << "_gamma=" << gamma << "_gray.png";
198  display(I_display, I_color_res, I_color_gamma_correction, I_gray_res, I_gray_gamma_correction, I_gray_display,
199  "Gamma correction. Click to continue.", ss_color.str(), ss_gray.str());
200 
201  // Display results for the different Gamma correction method
202  for (int gamma_idx = 0; gamma_idx < VISP_NAMESPACE_NAME::GAMMA_METHOD_COUNT; ++gamma_idx) {
203  gamma = -1.;
204  VISP_NAMESPACE_NAME::vpGammaMethod gamma_method = static_cast<VISP_NAMESPACE_NAME::vpGammaMethod>(gamma_idx);
205  if (gamma_method == VISP_NAMESPACE_NAME::GAMMA_MANUAL) {
206  continue;
207  }
208 
209  vpImage<vpRGBa> I_color_gamma_correction;
210  VISP_NAMESPACE_NAME::gammaCorrection(I_color, I_color_gamma_correction, static_cast<float>(gamma), colorHandling,
211  gamma_method);
212  vpImage<unsigned char> I_gray_gamma_correction;
213  VISP_NAMESPACE_NAME::gammaCorrection(I_gray, I_gray_gamma_correction, static_cast<float>(gamma), gamma_method);
214 
215  const std::string gamma_name = VISP_NAMESPACE_NAME::vpGammaMethodToString(gamma_method);
216  ss_color.str("");
217  ss_color << input_name << "_" << gamma_name << ".png";
218  ss_gray.str("");
219  ss_gray << input_name << "_" << gamma_name << "_gray.png";
220  display(I_display, I_color_res, I_color_gamma_correction, I_gray_res, I_gray_gamma_correction, I_gray_display,
221  "Gamma correction. Click to continue.", ss_color.str(), ss_gray.str(), gamma_name);
222  }
223 
225  vpImage<vpRGBa> I_color_equalize_histogram;
226  VISP_NAMESPACE_NAME::equalizeHistogram(I_color, I_color_equalize_histogram);
227  vpImage<unsigned char> I_gray_equalize_histogram;
228  VISP_NAMESPACE_NAME::equalizeHistogram(I_gray, I_gray_equalize_histogram);
230 
231  ss_color.str("");
232  ss_color << input_name << "_eqHist.png";
233  ss_gray.str("");
234  ss_gray << input_name << "_eqHist_gray.png";
235  display(I_display, I_color_res, I_color_equalize_histogram, I_gray_res, I_gray_equalize_histogram, I_gray_display,
236  "Histogram equalization. Click to continue.", ss_color.str(), ss_gray.str());
237 
239  vpImage<vpRGBa> I_color_retinex;
240  VISP_NAMESPACE_NAME::retinex(I_color, I_color_retinex, scale, scaleDiv, level, dynamic, kernelSize);
241  // Retinex uses color image as input
242  // Convert gray image into RGBa format for quick test
243  vpImage<vpRGBa> I_gray_color;
244  vpImageConvert::convert(I_gray, I_gray_color);
245  vpImage<vpRGBa> I_gray_color_retinex;
246  VISP_NAMESPACE_NAME::retinex(I_gray_color, I_gray_color_retinex, scale, scaleDiv, level, dynamic, kernelSize);
247  // Convert back to gray
248  vpImage<unsigned char> I_gray_retinex;
249  vpImageConvert::convert(I_gray_color_retinex, I_gray_retinex);
251 
252  ss_color.str("");
253  ss_color << input_name << "_Retinex_scale=" << scale << "_scaleDiv=" << scaleDiv << "_level=" << level
254  << "_dynamic=" << dynamic << "_kernelSize=" << kernelSize << ".png";
255  ss_gray.str("");
256  ss_gray << input_name << "_Retinex_scale=" << scale << "_scaleDiv=" << scaleDiv << "_level=" << level
257  << "_dynamic=" << dynamic << "_kernelSize=" << kernelSize << "_gray.png";
258  display(I_display, I_color_res, I_color_retinex, I_gray_res, I_gray_retinex, I_gray_display,
259  "Retinex. Click to quit.", ss_color.str(), ss_gray.str());
260 #else
261  (void)argc;
262  (void)argv;
263 #endif
264  return EXIT_SUCCESS;
265 }
static const vpColor red
Definition: vpColor.h:217
static const vpColor green
Definition: vpColor.h:220
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") VP_OVERRIDE
void setDownScalingFactor(unsigned int scale)
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:291
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
unsigned int getWidth() const
Definition: vpImage.h:242
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:639
unsigned int getHeight() const
Definition: vpImage.h:181
static std::string getNameWE(const std::string &pathname)
Definition: vpIoTools.cpp:1227
VISP_EXPORT void adjust(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, double alpha, double beta)
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 retinex(VISP_NAMESPACE_ADDRESSING vpImage< VISP_NAMESPACE_ADDRESSING vpRGBa > &I, int scale=240, int scaleDiv=3, int level=RETINEX_UNIFORM, double dynamic=1.2, int kernelSize=-1)
VISP_EXPORT vpGammaMethod vpGammaMethodFromString(const std::string &name)
Cast a string into a vpGammaMethod.
Definition: vpImgproc.cpp:116
VISP_EXPORT vpGammaColorHandling vpGammaColorHandlingFromString(const std::string &name)
Cast a string into a vpGammaColorHandling.
Definition: vpImgproc.cpp:164
vpGammaColorHandling
How to handle color images when applying Gamma Correction.
Definition: vpImgproc.h:149
VISP_EXPORT std::string vpGammaMethodList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpGammaMethod.
Definition: vpImgproc.cpp:73
VISP_EXPORT std::string vpGammaColorHandlingList(const std::string &pref="<", const std::string &sep=" , ", const std::string &suf=">")
Get the list of available vpGammaColorHandling.
Definition: vpImgproc.cpp:133
vpGammaMethod
Gamma Correction automatic methods.
Definition: vpImgproc.h:100
VISP_EXPORT std::string vpGammaMethodToString(const vpGammaMethod &type)
Cast a vpGammaMethod into a string, to know its name.
Definition: vpImgproc.cpp:87
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.