mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-17 15:26:00 +08:00
photo: move TonemapDurand to opencv_contrib
This commit is contained in:

committed by
Alexander Alekhin

parent
09fc4303c8
commit
b53cb76458
@@ -1,2 +1,2 @@
|
||||
set(the_description "Addon to basic photo module")
|
||||
ocv_define_module(xphoto opencv_core opencv_imgproc WRAP python java)
|
||||
ocv_define_module(xphoto opencv_core opencv_imgproc opencv_photo WRAP python java)
|
||||
|
@@ -6,7 +6,6 @@
|
||||
year={2012},
|
||||
publisher={Springer}
|
||||
}
|
||||
|
||||
@inproceedings{Cheng2015,
|
||||
title={Effective learning-based illuminant estimation using simple features},
|
||||
author={Cheng, Dongliang and Price, Brian and Cohen, Scott and Brown, Michael S},
|
||||
@@ -14,3 +13,14 @@
|
||||
pages={1000--1008},
|
||||
year={2015}
|
||||
}
|
||||
@inproceedings{DD02,
|
||||
author = {Durand, Fr{\'e}do and Dorsey, Julie},
|
||||
title = {Fast bilateral filtering for the display of high-dynamic-range images},
|
||||
booktitle = {ACM Transactions on Graphics (TOG)},
|
||||
year = {2002},
|
||||
pages = {257--266},
|
||||
volume = {21},
|
||||
number = {3},
|
||||
publisher = {ACM},
|
||||
url = {https://www.researchgate.net/profile/Julie_Dorsey/publication/220184746_Fast_Bilateral_Filtering_for_the_Display_of_High_-_dynamic_-_range_Images/links/54566b000cf26d5090a95f96/Fast-Bilateral-Filtering-for-the-Display-of-High-dynamic-range-Images.pdf}
|
||||
}
|
||||
|
@@ -50,4 +50,6 @@
|
||||
#include "xphoto/white_balance.hpp"
|
||||
#include "xphoto/dct_image_denoising.hpp"
|
||||
#include "xphoto/bm3d_image_denoising.hpp"
|
||||
#include "xphoto/tonemap.hpp"
|
||||
|
||||
#endif
|
||||
|
56
modules/xphoto/include/opencv2/xphoto/tonemap.hpp
Normal file
56
modules/xphoto/include/opencv2/xphoto/tonemap.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_XPHOTO_TONEMAP_HPP
|
||||
#define OPENCV_XPHOTO_TONEMAP_HPP
|
||||
|
||||
#include "opencv2/photo.hpp"
|
||||
|
||||
namespace cv { namespace xphoto {
|
||||
|
||||
//! @addtogroup xphoto
|
||||
//! @{
|
||||
|
||||
/** @brief This algorithm decomposes image into two layers: base layer and detail layer using bilateral filter
|
||||
and compresses contrast of the base layer thus preserving all the details.
|
||||
|
||||
This implementation uses regular bilateral filter from OpenCV.
|
||||
|
||||
Saturation enhancement is possible as in cv::TonemapDrago.
|
||||
|
||||
For more information see @cite DD02 .
|
||||
*/
|
||||
class CV_EXPORTS_W TonemapDurand : public Tonemap
|
||||
{
|
||||
public:
|
||||
|
||||
CV_WRAP virtual float getSaturation() const = 0;
|
||||
CV_WRAP virtual void setSaturation(float saturation) = 0;
|
||||
|
||||
CV_WRAP virtual float getContrast() const = 0;
|
||||
CV_WRAP virtual void setContrast(float contrast) = 0;
|
||||
|
||||
CV_WRAP virtual float getSigmaSpace() const = 0;
|
||||
CV_WRAP virtual void setSigmaSpace(float sigma_space) = 0;
|
||||
|
||||
CV_WRAP virtual float getSigmaColor() const = 0;
|
||||
CV_WRAP virtual void setSigmaColor(float sigma_color) = 0;
|
||||
};
|
||||
|
||||
/** @brief Creates TonemapDurand object
|
||||
|
||||
You need to set the OPENCV_ENABLE_NONFREE option in cmake to use those. Use them at your own risk.
|
||||
|
||||
@param gamma gamma value for gamma correction. See createTonemap
|
||||
@param contrast resulting contrast on logarithmic scale, i. e. log(max / min), where max and min
|
||||
are maximum and minimum luminance values of the resulting image.
|
||||
@param saturation saturation enhancement value. See createTonemapDrago
|
||||
@param sigma_space bilateral filter sigma in color space
|
||||
@param sigma_color bilateral filter sigma in coordinate space
|
||||
*/
|
||||
CV_EXPORTS_W Ptr<TonemapDurand>
|
||||
createTonemapDurand(float gamma = 1.0f, float contrast = 4.0f, float saturation = 1.0f, float sigma_space = 2.0f, float sigma_color = 2.0f);
|
||||
|
||||
}} // namespace
|
||||
#endif // OPENCV_XPHOTO_TONEMAP_HPP
|
129
modules/xphoto/src/tonemap.cpp
Normal file
129
modules/xphoto/src/tonemap.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/core/utils/trace.hpp>
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/xphoto.hpp"
|
||||
|
||||
namespace cv { namespace xphoto {
|
||||
|
||||
#ifdef OPENCV_ENABLE_NONFREE
|
||||
static inline
|
||||
void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation)
|
||||
{
|
||||
std::vector<Mat> channels(3);
|
||||
split(src, channels);
|
||||
for(int i = 0; i < 3; i++) {
|
||||
channels[i] = channels[i].mul(1.0f / lum);
|
||||
pow(channels[i], saturation, channels[i]);
|
||||
channels[i] = channels[i].mul(new_lum);
|
||||
}
|
||||
merge(channels, dst);
|
||||
}
|
||||
|
||||
static inline
|
||||
void log_(const Mat& src, Mat& dst)
|
||||
{
|
||||
max(src, Scalar::all(1e-4), dst);
|
||||
log(dst, dst);
|
||||
}
|
||||
|
||||
class TonemapDurandImpl CV_FINAL : public TonemapDurand
|
||||
{
|
||||
public:
|
||||
TonemapDurandImpl(float _gamma, float _contrast, float _saturation, float _sigma_color, float _sigma_space) :
|
||||
name("TonemapDurand"),
|
||||
gamma(_gamma),
|
||||
contrast(_contrast),
|
||||
saturation(_saturation),
|
||||
sigma_color(_sigma_color),
|
||||
sigma_space(_sigma_space)
|
||||
{
|
||||
}
|
||||
|
||||
void process(InputArray _src, OutputArray _dst) CV_OVERRIDE
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
Mat src = _src.getMat();
|
||||
CV_Assert(!src.empty());
|
||||
_dst.create(src.size(), CV_32FC3);
|
||||
Mat img = _dst.getMat();
|
||||
Ptr<Tonemap> linear = createTonemap(1.0f);
|
||||
linear->process(src, img);
|
||||
|
||||
Mat gray_img;
|
||||
cvtColor(img, gray_img, COLOR_RGB2GRAY);
|
||||
Mat log_img;
|
||||
log_(gray_img, log_img);
|
||||
Mat map_img;
|
||||
bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space);
|
||||
|
||||
double min, max;
|
||||
minMaxLoc(map_img, &min, &max);
|
||||
float scale = contrast / static_cast<float>(max - min);
|
||||
exp(map_img * (scale - 1.0f) + log_img, map_img);
|
||||
log_img.release();
|
||||
|
||||
mapLuminance(img, img, gray_img, map_img, saturation);
|
||||
pow(img, 1.0f / gamma, img);
|
||||
}
|
||||
|
||||
float getGamma() const CV_OVERRIDE { return gamma; }
|
||||
void setGamma(float val) CV_OVERRIDE { gamma = val; }
|
||||
|
||||
float getSaturation() const CV_OVERRIDE { return saturation; }
|
||||
void setSaturation(float val) CV_OVERRIDE { saturation = val; }
|
||||
|
||||
float getContrast() const CV_OVERRIDE { return contrast; }
|
||||
void setContrast(float val) CV_OVERRIDE { contrast = val; }
|
||||
|
||||
float getSigmaColor() const CV_OVERRIDE { return sigma_color; }
|
||||
void setSigmaColor(float val) CV_OVERRIDE { sigma_color = val; }
|
||||
|
||||
float getSigmaSpace() const CV_OVERRIDE { return sigma_space; }
|
||||
void setSigmaSpace(float val) CV_OVERRIDE { sigma_space = val; }
|
||||
|
||||
void write(FileStorage& fs) const CV_OVERRIDE
|
||||
{
|
||||
writeFormat(fs);
|
||||
fs << "name" << name
|
||||
<< "gamma" << gamma
|
||||
<< "contrast" << contrast
|
||||
<< "sigma_color" << sigma_color
|
||||
<< "sigma_space" << sigma_space
|
||||
<< "saturation" << saturation;
|
||||
}
|
||||
|
||||
void read(const FileNode& fn) CV_OVERRIDE
|
||||
{
|
||||
FileNode n = fn["name"];
|
||||
CV_Assert(n.isString() && String(n) == name);
|
||||
gamma = fn["gamma"];
|
||||
contrast = fn["contrast"];
|
||||
sigma_color = fn["sigma_color"];
|
||||
sigma_space = fn["sigma_space"];
|
||||
saturation = fn["saturation"];
|
||||
}
|
||||
|
||||
protected:
|
||||
String name;
|
||||
float gamma, contrast, saturation, sigma_color, sigma_space;
|
||||
};
|
||||
|
||||
Ptr<TonemapDurand> createTonemapDurand(float gamma, float contrast, float saturation, float sigma_color, float sigma_space)
|
||||
{
|
||||
return makePtr<TonemapDurandImpl>(gamma, contrast, saturation, sigma_color, sigma_space);
|
||||
}
|
||||
#else
|
||||
Ptr<TonemapDurand> createTonemapDurand(float /*gamma*/, float /*contrast*/, float /*saturation*/, float /*sigma_color*/, float /*sigma_space*/)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
"This algorithm is patented and is excluded in this configuration; "
|
||||
"Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library");
|
||||
}
|
||||
#endif // OPENCV_ENABLE_NONFREE
|
||||
|
||||
}} // namespace
|
43
modules/xphoto/test/test_hdr.cpp
Normal file
43
modules/xphoto/test/test_hdr.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
using namespace cv::xphoto;
|
||||
|
||||
#ifdef OPENCV_ENABLE_NONFREE
|
||||
|
||||
void loadImage(string path, Mat &img)
|
||||
{
|
||||
img = imread(path, -1);
|
||||
ASSERT_FALSE(img.empty()) << "Could not load input image " << path;
|
||||
}
|
||||
|
||||
void checkEqual(Mat img0, Mat img1, double threshold, const string& name)
|
||||
{
|
||||
double max = 1.0;
|
||||
minMaxLoc(abs(img0 - img1), NULL, &max);
|
||||
ASSERT_FALSE(max > threshold) << "max=" << max << " threshold=" << threshold << " method=" << name;
|
||||
}
|
||||
|
||||
TEST(Photo_Tonemap, Durand_regression)
|
||||
{
|
||||
string test_path = string(cvtest::TS::ptr()->get_data_path()) + "cv/hdr/tonemap/";
|
||||
|
||||
Mat img, expected, result;
|
||||
loadImage(test_path + "image.hdr", img);
|
||||
float gamma = 2.2f;
|
||||
|
||||
Ptr<TonemapDurand> durand = createTonemapDurand(gamma);
|
||||
durand->process(img, result);
|
||||
loadImage(test_path + "durand.png", expected);
|
||||
result.convertTo(result, CV_8UC3, 255);
|
||||
checkEqual(result, expected, 3, "Durand");
|
||||
}
|
||||
|
||||
#endif // OPENCV_ENABLE_NONFREE
|
||||
|
||||
}} // namespace
|
Reference in New Issue
Block a user