Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update brightness tutorial #1482

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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);

Check warning on line 337 in modules/imgproc/src/vpImgproc.cpp

View check run for this annotation

Codecov / codecov/patch

modules/imgproc/src/vpImgproc.cpp#L337

Added line #L337 was not covered by tests
}

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
Loading