Skip to content

Commit

Permalink
Merge pull request #1482 from s-trinh/update_tuto_brightness_cycle_ga…
Browse files Browse the repository at this point in the history
…mma_methods

Update brightness tutorial
  • Loading branch information
fspindle authored Nov 5, 2024
2 parents b4ad052 + db58506 commit e7b2a9f
Show file tree
Hide file tree
Showing 4 changed files with 473 additions and 87 deletions.
3 changes: 1 addition & 2 deletions modules/imgproc/src/vpImgproc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,12 @@ void gammaCorrectionLogMethod(vpImage<unsigned char> &I, const vpImage<bool> *p_
unsigned char inputRange = inputMax - inputMin;

float gamma_computed = static_cast<float>((std::log(128.f) - std::log(256.f)) / (std::log(mean) - std::log(inputRange)));
float inverse_gamma = 1.f / gamma_computed;

// Construct the look-up table
unsigned char lut[256];
float inputRangeAsFloat = static_cast<float>(inputRange);
for (unsigned int i = inputMin; i <= inputMax; ++i) {
lut[i] = vpMath::saturate<unsigned char>(std::pow(static_cast<float>(i - inputMin) / inputRangeAsFloat, inverse_gamma) * 255.f);
lut[i] = vpMath::saturate<unsigned char>(std::pow(static_cast<float>(i - inputMin) / inputRangeAsFloat, gamma_computed) * 255.f);
}

I.performLut(lut);
Expand Down
4 changes: 3 additions & 1 deletion tutorial/imgproc/brightness/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ find_package(VISP REQUIRED visp_core visp_io visp_gui visp_imgproc)

# set the list of source files
set(tutorial_cpp
tutorial-brightness-adjustment.cpp)
tutorial-brightness-adjustment.cpp
tutorial-compare-auto-gamma.cpp
)

list(APPEND tutorial_data "${CMAKE_CURRENT_SOURCE_DIR}/Sample_low_brightness.png")

Expand Down
234 changes: 150 additions & 84 deletions tutorial/imgproc/brightness/tutorial-brightness-adjustment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
#include <iostream>
#include <visp3/core/vpConfig.h>
#include <visp3/core/vpImage.h>
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayOpenCV.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/gui/vpDisplayFactory.h>
#include <visp3/io/vpImageIo.h>

#if defined(VISP_HAVE_MODULE_IMGPROC)
Expand All @@ -15,17 +14,49 @@
//! [Include]
#endif

#if ((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
#include <memory>
#endif

#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

namespace
{
void display(vpImage<vpRGBa> &I_display, vpImage<vpRGBa> &I_color_res, const vpImage<vpRGBa> &I_color_adjust,
vpImage<unsigned char> &I_gray_res, vpImage<unsigned char> &I_gray_adjust, vpImage<vpRGBa> &I_gray_display,
const std::string &title, const std::string &filename_color, const std::string &filename_gray,
const std::string &title_2 = "")
{
I_color_res.insert(I_color_adjust, vpImagePoint(0, I_color_adjust.getWidth()));
I_display.insert(I_color_adjust, vpImagePoint(0, I_color_adjust.getWidth()));

I_gray_res.insert(I_gray_adjust, vpImagePoint(0, I_gray_adjust.getWidth()));
vpImageConvert::convert(I_gray_adjust, I_gray_display);
I_display.insert(I_gray_display, vpImagePoint(I_color_adjust.getHeight(), I_color_adjust.getWidth()));

vpImageIo::write(I_color_res, filename_color);
vpImageIo::write(I_gray_res, filename_gray);

vpDisplay::display(I_display);
vpDisplay::displayText(I_display, 20, 20, title, vpColor::red);
if (!title_2.empty()) {
vpDisplay::displayText(I_display, 40, static_cast<unsigned int>(I_color_adjust.getWidth()*0.85),
title_2, vpColor::green);
}
vpDisplay::flush(I_display);
vpDisplay::getClick(I_display);
}
}

int main(int argc, const char **argv)
{
//! [Macro defined]
#if defined(VISP_HAVE_MODULE_IMGPROC) && \
(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)) && \
(defined(VISP_HAVE_PNG) || defined(VISP_HAVE_OPENCV))
//! [Macro defined]
//!
#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif
#if defined(VISP_HAVE_MODULE_IMGPROC) && defined(VISP_HAVE_DISPLAY) && \
(defined(VISP_HAVE_PNG) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_STBIMAGE) || defined(VISP_HAVE_SIMDLIB)) && \
((__cplusplus >= 201103L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)))
//! [Macro defined]

std::string input_filename = "Sample_low_brightness.png";
double alpha = 10.0, beta = 50.0;
Expand All @@ -34,19 +65,24 @@ int main(int argc, const char **argv)
VISP_NAMESPACE_NAME::vpGammaColorHandling colorHandling = VISP_NAMESPACE_NAME::GAMMA_HSV;
int scale = 240, scaleDiv = 3, level = 0, kernelSize = -1;
double dynamic = 3.0;
int scale_display = 2;

for (int i = 1; i < argc; i++) {
if (std::string(argv[i]) == "--input" && i + 1 < argc) {
input_filename = std::string(argv[i + 1]);
++i;
input_filename = std::string(argv[i]);
}
else if (std::string(argv[i]) == "--alpha" && i + 1 < argc) {
alpha = atof(argv[i + 1]);
++i;
alpha = atof(argv[i]);
}
else if (std::string(argv[i]) == "--beta" && i + 1 < argc) {
beta = atof(argv[i + 1]);
++i;
beta = atof(argv[i]);
}
else if (std::string(argv[i]) == "--gamma" && i + 1 < argc) {
gamma = atof(argv[i + 1]);
++i;
gamma = atof(argv[i]);
}
else if ((std::string(argv[i]) == "--gamma-color-handling") && ((i + 1) < argc)) {
++i;
Expand All @@ -57,71 +93,83 @@ int main(int argc, const char **argv)
method = VISP_NAMESPACE_NAME::vpGammaMethodFromString(argv[i]);
}
else if (std::string(argv[i]) == "--scale" && i + 1 < argc) {
scale = atoi(argv[i + 1]);
++i;
scale = atoi(argv[i]);
}
else if (std::string(argv[i]) == "--scaleDiv" && i + 1 < argc) {
scaleDiv = atoi(argv[i + 1]);
++i;
scaleDiv = atoi(argv[i]);
}
else if (std::string(argv[i]) == "--level" && i + 1 < argc) {
level = atoi(argv[i + 1]);
++i;
level = atoi(argv[i]);
}
else if (std::string(argv[i]) == "--kernelSize" && i + 1 < argc) {
kernelSize = atoi(argv[i + 1]);
++i;
kernelSize = atoi(argv[i]);
}
else if (std::string(argv[i]) == "--dynamic" && i + 1 < argc) {
dynamic = atof(argv[i + 1]);
++i;
dynamic = atof(argv[i]);
}
else if (std::string(argv[i]) == "--scale-display" && i + 1 < argc) {
++i;
scale_display = atoi(argv[i]);
}
else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
std::cout << "Usage: " << argv[0]
<< " [--input <input image>]"
" [--alpha <alpha for VISP_NAMESPACE_NAME::adjust()>] [--beta <beta for "
"VISP_NAMESPACE_NAME::adjust()>]"
" [--gamma <gamma for VISP_NAMESPACE_NAME::gammaCorrection()>]"
" [--alpha <alpha for adjust()>] [--beta <beta for adjust()>]"
" [--gamma <gamma for gammaCorrection()>]"
" [--gamma-color-handling " << VISP_NAMESPACE_NAME::vpGammaColorHandlingList() << "]"
" [--gamma-method " << VISP_NAMESPACE_NAME::vpGammaMethodList() << "]"
" [--scale <scale for VISP_NAMESPACE_NAME::retinex()> [--scaleDiv for "
"VISP_NAMESPACE_NAME::retinex()]"
" [--level <level for VISP_NAMESPACE_NAME::retinex()> [--kernelSize "
"<kernelSize for VISP_NAMESPACE_NAME::retinex()>]"
" [--dynamic <dynamic for VISP_NAMESPACE_NAME::retinex()>] [--help]"
" [--scale <scale for retinex()> [--scaleDiv for retinex()]"
" [--level <level for retinex()> [--kernelSize <kernelSize for retinex()>]"
" [--dynamic <dynamic for retinex()>] "
" [--scale-display <display downscaling factor>] "
" [--help]"
<< std::endl;
return EXIT_SUCCESS;
}
}

// Filename without extension to save the results
const std::string input_name = vpIoTools::getNameWE(input_filename);

vpImage<vpRGBa> I_color;
vpImageIo::read(I_color, input_filename);
vpImage<unsigned char> I_gray;
vpImageConvert::convert(I_color, I_gray);
vpImage<vpRGBa> I_gray_display;
vpImageConvert::convert(I_gray, I_gray_display);

// Side-by-side images
vpImage<vpRGBa> I_color_res(I_color.getHeight(), 2 * I_color.getWidth());
I_color_res.insert(I_color, vpImagePoint());
vpImage<unsigned char> I_gray_res(I_gray.getHeight(), 2 * I_gray.getWidth());
I_gray_res.insert(I_gray, vpImagePoint());
#ifdef VISP_HAVE_X11
vpDisplayX d_gray(I_gray_res);
vpDisplayX d(I_color_res);
#elif defined(VISP_HAVE_GDI)
vpDisplayGDI d_gray(I_gray_res);
vpDisplayGDI d(I_color_res);
#elif defined(HAVE_OPENCV_HIGHGUI)
vpDisplayOpenCV d_gray(I_gray_res);
vpDisplayOpenCV d(I_color_res);
#endif

// Side-by-side display for color (top) and gray (bottom) images
vpImage<vpRGBa> I_display(2 * I_color.getHeight(), 2 * I_color.getWidth());
I_display.insert(I_color, vpImagePoint());
I_display.insert(I_gray_display, vpImagePoint(I_color.getHeight(), 0));
std::shared_ptr<vpDisplay> d = vpDisplayFactory::createDisplay();
d->setDownScalingFactor(static_cast<vpDisplay::vpScaleType>(scale_display));
d->init(I_display, 10, 10, "Brightness adjustment results");

//! [Brightness contrast adjustment]
vpImage<vpRGBa> I_color_adjust;
VISP_NAMESPACE_NAME::adjust(I_color, I_color_adjust, alpha, beta);
vpImage<unsigned char> I_gray_adjust;
VISP_NAMESPACE_NAME::adjust(I_gray, I_gray_adjust, alpha, beta);
//! [Brightness contrast adjustment]
I_color_res.insert(I_color_adjust, vpImagePoint(0, I_color.getWidth()));
std::stringstream ss;
ss << "Sample_low_brightness_alpha=" << alpha << "_beta=" << beta << ".png";
vpImageIo::write(I_color_res, ss.str());

vpDisplay::display(I_color_res);
vpDisplay::displayText(I_color_res, 20, 20, "Brightness and contrast adjustment. Click to continue.", vpColor::red);
vpDisplay::flush(I_color_res);
vpDisplay::getClick(I_color_res);
std::stringstream ss_color;
ss_color << input_name << "_adjust_alpha=" << alpha << "_beta=" << beta << ".png";
std::stringstream ss_gray;
ss_gray << input_name << "_adjust_alpha=" << alpha << "_beta=" << beta << "_gray.png";
display(I_display, I_color_res, I_color_adjust, I_gray_res, I_gray_adjust, I_gray_display,
"Brightness and contrast adjustment. Click to continue.", ss_color.str(), ss_gray.str());

//! [Gamma correction]
if (method != VISP_NAMESPACE_NAME::GAMMA_MANUAL) {
Expand All @@ -133,60 +181,78 @@ int main(int argc, const char **argv)
// If the user wants to set a constant user-defined gamma factor, the method must be set to manual.
method = VISP_NAMESPACE_NAME::GAMMA_MANUAL;
}
vpImage<unsigned char> I_gray_gamma_correction;
VISP_NAMESPACE_NAME::gammaCorrection(I_gray, I_gray_gamma_correction, static_cast<float>(gamma), method);
vpImage<vpRGBa> I_color_gamma_correction;
VISP_NAMESPACE_NAME::gammaCorrection(I_color, I_color_gamma_correction, static_cast<float>(gamma), colorHandling, method);
vpImage<unsigned char> I_gray_gamma_correction;
VISP_NAMESPACE_NAME::gammaCorrection(I_gray, I_gray_gamma_correction, static_cast<float>(gamma), method);
//! [Gamma correction]
I_gray_res.insert(I_gray_gamma_correction, vpImagePoint(0, I_gray.getWidth()));
ss.str("");
ss << "Sample_low_brightness_gray.png";
vpImageIo::write(I_gray_res, ss.str());

vpDisplay::display(I_gray_res);
vpDisplay::displayText(I_gray_res, 20, 20, "Gamma correction on gray image. Click to continue.", vpColor::red);
vpDisplay::flush(I_gray_res);
vpDisplay::getClick(I_gray_res);

I_color_res.insert(I_color_gamma_correction, vpImagePoint(0, I_color.getWidth()));
ss.str("");
ss << "Sample_low_brightness_gamma=" << gamma << ".png";
vpImageIo::write(I_color_res, ss.str());

vpDisplay::display(I_color_res);
vpDisplay::displayText(I_color_res, 20, 20, "Gamma correction. Click to continue.", vpColor::red);
vpDisplay::flush(I_color_res);
vpDisplay::getClick(I_color_res);

ss_color.str("");
ss_color << input_name << "_gamma=" << gamma << ".png";
ss_gray.str("");
ss_gray << input_name << "_gamma=" << gamma << "_gray.png";
display(I_display, I_color_res, I_color_gamma_correction, I_gray_res, I_gray_gamma_correction, I_gray_display,
"Gamma correction. Click to continue.", ss_color.str(), ss_gray.str());

// Display results for the different Gamma correction method
for (int gamma_idx = 0; gamma_idx < VISP_NAMESPACE_NAME::GAMMA_METHOD_COUNT; ++gamma_idx) {
gamma = -1.;
VISP_NAMESPACE_NAME::vpGammaMethod gamma_method = static_cast<VISP_NAMESPACE_NAME::vpGammaMethod>(gamma_idx);
if (gamma_method == VISP_NAMESPACE_NAME::GAMMA_MANUAL) {
continue;
}

vpImage<vpRGBa> I_color_gamma_correction;
VISP_NAMESPACE_NAME::gammaCorrection(I_color, I_color_gamma_correction, static_cast<float>(gamma), colorHandling,
gamma_method);
vpImage<unsigned char> I_gray_gamma_correction;
VISP_NAMESPACE_NAME::gammaCorrection(I_gray, I_gray_gamma_correction, static_cast<float>(gamma), gamma_method);

const std::string gamma_name = VISP_NAMESPACE_NAME::vpGammaMethodToString(gamma_method);
ss_color.str("");
ss_color << input_name << "_" << gamma_name << ".png";
ss_gray.str("");
ss_gray << input_name << "_" << gamma_name << "_gray.png";
display(I_display, I_color_res, I_color_gamma_correction, I_gray_res, I_gray_gamma_correction, I_gray_display,
"Gamma correction. Click to continue.", ss_color.str(), ss_gray.str(), gamma_name);
}

//! [Histogram equalization]
vpImage<vpRGBa> I_color_equalize_histogram;
VISP_NAMESPACE_NAME::equalizeHistogram(I_color, I_color_equalize_histogram);
vpImage<unsigned char> I_gray_equalize_histogram;
VISP_NAMESPACE_NAME::equalizeHistogram(I_gray, I_gray_equalize_histogram);
//! [Histogram equalization]
I_color_res.insert(I_color_equalize_histogram, vpImagePoint(0, I_color.getWidth()));
ss.str("");
ss << "Sample_low_brightness_eqHist.png";
vpImageIo::write(I_color_res, ss.str());

vpDisplay::display(I_color_res);
vpDisplay::displayText(I_color_res, 20, 20, "Histogram equalization. Click to continue.", vpColor::red);
vpDisplay::flush(I_color_res);
vpDisplay::getClick(I_color_res);
ss_color.str("");
ss_color << input_name << "_eqHist.png";
ss_gray.str("");
ss_gray << input_name << "_eqHist_gray.png";
display(I_display, I_color_res, I_color_equalize_histogram, I_gray_res, I_gray_equalize_histogram, I_gray_display,
"Histogram equalization. Click to continue.", ss_color.str(), ss_gray.str());

//! [Retinex]
vpImage<vpRGBa> I_color_retinex;
VISP_NAMESPACE_NAME::retinex(I_color, I_color_retinex, scale, scaleDiv, level, dynamic, kernelSize);
// Retinex uses color image as input
// Convert gray image into RGBa format for quick test
vpImage<vpRGBa> I_gray_color;
vpImageConvert::convert(I_gray, I_gray_color);
vpImage<vpRGBa> I_gray_color_retinex;
VISP_NAMESPACE_NAME::retinex(I_gray_color, I_gray_color_retinex, scale, scaleDiv, level, dynamic, kernelSize);
// Convert back to gray
vpImage<unsigned char> I_gray_retinex;
vpImageConvert::convert(I_gray_color_retinex, I_gray_retinex);
//! [Retinex]
I_color_res.insert(I_color_retinex, vpImagePoint(0, I_color.getWidth()));

ss.str("");
ss << "Sample_low_brightness_scale=" << scale << "_scaleDiv=" << scaleDiv << "_level=" << level
ss_color.str("");
ss_color << input_name << "_Retinex_scale=" << scale << "_scaleDiv=" << scaleDiv << "_level=" << level
<< "_dynamic=" << dynamic << "_kernelSize=" << kernelSize << ".png";
vpImageIo::write(I_color_res, ss.str());

vpDisplay::display(I_color_res);
vpDisplay::displayText(I_color_res, 20, 20, "Retinex. Click to quit.", vpColor::red);
vpDisplay::flush(I_color_res);
vpDisplay::getClick(I_color_res);
ss_gray.str("");
ss_gray << input_name << "_Retinex_scale=" << scale << "_scaleDiv=" << scaleDiv << "_level=" << level
<< "_dynamic=" << dynamic << "_kernelSize=" << kernelSize << "_gray.png";
display(I_display, I_color_res, I_color_retinex, I_gray_res, I_gray_retinex, I_gray_display,
"Retinex. Click to quit.", ss_color.str(), ss_gray.str());
#else
(void)argc;
(void)argv;
Expand Down
Loading

0 comments on commit e7b2a9f

Please sign in to comment.