Skip to content

Commit b53cb76

Browse files
committed
photo: move TonemapDurand to opencv_contrib
1 parent 09fc430 commit b53cb76

File tree

6 files changed

+242
-2
lines changed

6 files changed

+242
-2
lines changed

modules/xphoto/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
set(the_description "Addon to basic photo module")
2-
ocv_define_module(xphoto opencv_core opencv_imgproc WRAP python java)
2+
ocv_define_module(xphoto opencv_core opencv_imgproc opencv_photo WRAP python java)

modules/xphoto/doc/xphoto.bib

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,21 @@ @incollection{He2012
66
year={2012},
77
publisher={Springer}
88
}
9-
109
@inproceedings{Cheng2015,
1110
title={Effective learning-based illuminant estimation using simple features},
1211
author={Cheng, Dongliang and Price, Brian and Cohen, Scott and Brown, Michael S},
1312
booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
1413
pages={1000--1008},
1514
year={2015}
1615
}
16+
@inproceedings{DD02,
17+
author = {Durand, Fr{\'e}do and Dorsey, Julie},
18+
title = {Fast bilateral filtering for the display of high-dynamic-range images},
19+
booktitle = {ACM Transactions on Graphics (TOG)},
20+
year = {2002},
21+
pages = {257--266},
22+
volume = {21},
23+
number = {3},
24+
publisher = {ACM},
25+
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}
26+
}

modules/xphoto/include/opencv2/xphoto.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,6 @@
5050
#include "xphoto/white_balance.hpp"
5151
#include "xphoto/dct_image_denoising.hpp"
5252
#include "xphoto/bm3d_image_denoising.hpp"
53+
#include "xphoto/tonemap.hpp"
54+
5355
#endif
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#ifndef OPENCV_XPHOTO_TONEMAP_HPP
6+
#define OPENCV_XPHOTO_TONEMAP_HPP
7+
8+
#include "opencv2/photo.hpp"
9+
10+
namespace cv { namespace xphoto {
11+
12+
//! @addtogroup xphoto
13+
//! @{
14+
15+
/** @brief This algorithm decomposes image into two layers: base layer and detail layer using bilateral filter
16+
and compresses contrast of the base layer thus preserving all the details.
17+
18+
This implementation uses regular bilateral filter from OpenCV.
19+
20+
Saturation enhancement is possible as in cv::TonemapDrago.
21+
22+
For more information see @cite DD02 .
23+
*/
24+
class CV_EXPORTS_W TonemapDurand : public Tonemap
25+
{
26+
public:
27+
28+
CV_WRAP virtual float getSaturation() const = 0;
29+
CV_WRAP virtual void setSaturation(float saturation) = 0;
30+
31+
CV_WRAP virtual float getContrast() const = 0;
32+
CV_WRAP virtual void setContrast(float contrast) = 0;
33+
34+
CV_WRAP virtual float getSigmaSpace() const = 0;
35+
CV_WRAP virtual void setSigmaSpace(float sigma_space) = 0;
36+
37+
CV_WRAP virtual float getSigmaColor() const = 0;
38+
CV_WRAP virtual void setSigmaColor(float sigma_color) = 0;
39+
};
40+
41+
/** @brief Creates TonemapDurand object
42+
43+
You need to set the OPENCV_ENABLE_NONFREE option in cmake to use those. Use them at your own risk.
44+
45+
@param gamma gamma value for gamma correction. See createTonemap
46+
@param contrast resulting contrast on logarithmic scale, i. e. log(max / min), where max and min
47+
are maximum and minimum luminance values of the resulting image.
48+
@param saturation saturation enhancement value. See createTonemapDrago
49+
@param sigma_space bilateral filter sigma in color space
50+
@param sigma_color bilateral filter sigma in coordinate space
51+
*/
52+
CV_EXPORTS_W Ptr<TonemapDurand>
53+
createTonemapDurand(float gamma = 1.0f, float contrast = 4.0f, float saturation = 1.0f, float sigma_space = 2.0f, float sigma_color = 2.0f);
54+
55+
}} // namespace
56+
#endif // OPENCV_XPHOTO_TONEMAP_HPP

modules/xphoto/src/tonemap.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#include <opencv2/core.hpp>
6+
#include <opencv2/core/utils/trace.hpp>
7+
#include "opencv2/imgproc.hpp"
8+
#include "opencv2/xphoto.hpp"
9+
10+
namespace cv { namespace xphoto {
11+
12+
#ifdef OPENCV_ENABLE_NONFREE
13+
static inline
14+
void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation)
15+
{
16+
std::vector<Mat> channels(3);
17+
split(src, channels);
18+
for(int i = 0; i < 3; i++) {
19+
channels[i] = channels[i].mul(1.0f / lum);
20+
pow(channels[i], saturation, channels[i]);
21+
channels[i] = channels[i].mul(new_lum);
22+
}
23+
merge(channels, dst);
24+
}
25+
26+
static inline
27+
void log_(const Mat& src, Mat& dst)
28+
{
29+
max(src, Scalar::all(1e-4), dst);
30+
log(dst, dst);
31+
}
32+
33+
class TonemapDurandImpl CV_FINAL : public TonemapDurand
34+
{
35+
public:
36+
TonemapDurandImpl(float _gamma, float _contrast, float _saturation, float _sigma_color, float _sigma_space) :
37+
name("TonemapDurand"),
38+
gamma(_gamma),
39+
contrast(_contrast),
40+
saturation(_saturation),
41+
sigma_color(_sigma_color),
42+
sigma_space(_sigma_space)
43+
{
44+
}
45+
46+
void process(InputArray _src, OutputArray _dst) CV_OVERRIDE
47+
{
48+
CV_TRACE_FUNCTION();
49+
50+
Mat src = _src.getMat();
51+
CV_Assert(!src.empty());
52+
_dst.create(src.size(), CV_32FC3);
53+
Mat img = _dst.getMat();
54+
Ptr<Tonemap> linear = createTonemap(1.0f);
55+
linear->process(src, img);
56+
57+
Mat gray_img;
58+
cvtColor(img, gray_img, COLOR_RGB2GRAY);
59+
Mat log_img;
60+
log_(gray_img, log_img);
61+
Mat map_img;
62+
bilateralFilter(log_img, map_img, -1, sigma_color, sigma_space);
63+
64+
double min, max;
65+
minMaxLoc(map_img, &min, &max);
66+
float scale = contrast / static_cast<float>(max - min);
67+
exp(map_img * (scale - 1.0f) + log_img, map_img);
68+
log_img.release();
69+
70+
mapLuminance(img, img, gray_img, map_img, saturation);
71+
pow(img, 1.0f / gamma, img);
72+
}
73+
74+
float getGamma() const CV_OVERRIDE { return gamma; }
75+
void setGamma(float val) CV_OVERRIDE { gamma = val; }
76+
77+
float getSaturation() const CV_OVERRIDE { return saturation; }
78+
void setSaturation(float val) CV_OVERRIDE { saturation = val; }
79+
80+
float getContrast() const CV_OVERRIDE { return contrast; }
81+
void setContrast(float val) CV_OVERRIDE { contrast = val; }
82+
83+
float getSigmaColor() const CV_OVERRIDE { return sigma_color; }
84+
void setSigmaColor(float val) CV_OVERRIDE { sigma_color = val; }
85+
86+
float getSigmaSpace() const CV_OVERRIDE { return sigma_space; }
87+
void setSigmaSpace(float val) CV_OVERRIDE { sigma_space = val; }
88+
89+
void write(FileStorage& fs) const CV_OVERRIDE
90+
{
91+
writeFormat(fs);
92+
fs << "name" << name
93+
<< "gamma" << gamma
94+
<< "contrast" << contrast
95+
<< "sigma_color" << sigma_color
96+
<< "sigma_space" << sigma_space
97+
<< "saturation" << saturation;
98+
}
99+
100+
void read(const FileNode& fn) CV_OVERRIDE
101+
{
102+
FileNode n = fn["name"];
103+
CV_Assert(n.isString() && String(n) == name);
104+
gamma = fn["gamma"];
105+
contrast = fn["contrast"];
106+
sigma_color = fn["sigma_color"];
107+
sigma_space = fn["sigma_space"];
108+
saturation = fn["saturation"];
109+
}
110+
111+
protected:
112+
String name;
113+
float gamma, contrast, saturation, sigma_color, sigma_space;
114+
};
115+
116+
Ptr<TonemapDurand> createTonemapDurand(float gamma, float contrast, float saturation, float sigma_color, float sigma_space)
117+
{
118+
return makePtr<TonemapDurandImpl>(gamma, contrast, saturation, sigma_color, sigma_space);
119+
}
120+
#else
121+
Ptr<TonemapDurand> createTonemapDurand(float /*gamma*/, float /*contrast*/, float /*saturation*/, float /*sigma_color*/, float /*sigma_space*/)
122+
{
123+
CV_Error(Error::StsNotImplemented,
124+
"This algorithm is patented and is excluded in this configuration; "
125+
"Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library");
126+
}
127+
#endif // OPENCV_ENABLE_NONFREE
128+
129+
}} // namespace

modules/xphoto/test/test_hdr.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#include "test_precomp.hpp"
6+
7+
namespace opencv_test { namespace {
8+
9+
using namespace cv::xphoto;
10+
11+
#ifdef OPENCV_ENABLE_NONFREE
12+
13+
void loadImage(string path, Mat &img)
14+
{
15+
img = imread(path, -1);
16+
ASSERT_FALSE(img.empty()) << "Could not load input image " << path;
17+
}
18+
19+
void checkEqual(Mat img0, Mat img1, double threshold, const string& name)
20+
{
21+
double max = 1.0;
22+
minMaxLoc(abs(img0 - img1), NULL, &max);
23+
ASSERT_FALSE(max > threshold) << "max=" << max << " threshold=" << threshold << " method=" << name;
24+
}
25+
26+
TEST(Photo_Tonemap, Durand_regression)
27+
{
28+
string test_path = string(cvtest::TS::ptr()->get_data_path()) + "cv/hdr/tonemap/";
29+
30+
Mat img, expected, result;
31+
loadImage(test_path + "image.hdr", img);
32+
float gamma = 2.2f;
33+
34+
Ptr<TonemapDurand> durand = createTonemapDurand(gamma);
35+
durand->process(img, result);
36+
loadImage(test_path + "durand.png", expected);
37+
result.convertTo(result, CV_8UC3, 255);
38+
checkEqual(result, expected, 3, "Durand");
39+
}
40+
41+
#endif // OPENCV_ENABLE_NONFREE
42+
43+
}} // namespace

0 commit comments

Comments
 (0)