Merge pull request #1932 from alalek:photo_move_durand_contrib
commit
4bf1ccec25
6 changed files with 242 additions and 2 deletions
@ -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) |
||||
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in new issue