mirror of
https://github.com/opencv/opencv.git
synced 2024-11-26 04:00:30 +08:00
Merge pull request #13362 from alalek:photo_move_durand_contrib
This commit is contained in:
commit
838624bf53
@ -180,17 +180,6 @@
|
|||||||
volume = {9},
|
volume = {9},
|
||||||
publisher = {Walter de Gruyter}
|
publisher = {Walter de Gruyter}
|
||||||
}
|
}
|
||||||
@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}
|
|
||||||
}
|
|
||||||
@inproceedings{DM03,
|
@inproceedings{DM03,
|
||||||
author = {Drago, Fr{\'e}d{\'e}ric and Myszkowski, Karol and Annen, Thomas and Chiba, Norishige},
|
author = {Drago, Fr{\'e}d{\'e}ric and Myszkowski, Karol and Annen, Thomas and Chiba, Norishige},
|
||||||
title = {Adaptive logarithmic mapping for displaying high contrast scenes},
|
title = {Adaptive logarithmic mapping for displaying high contrast scenes},
|
||||||
|
@ -85,10 +85,8 @@ we will later have to clip the data in order to avoid overflow.
|
|||||||
|
|
||||||
@code{.py}
|
@code{.py}
|
||||||
# Tonemap HDR image
|
# Tonemap HDR image
|
||||||
tonemap1 = cv.createTonemapDurand(gamma=2.2)
|
tonemap1 = cv.createTonemap(gamma=2.2)
|
||||||
res_debevec = tonemap1.process(hdr_debevec.copy())
|
res_debevec = tonemap1.process(hdr_debevec.copy())
|
||||||
tonemap2 = cv.createTonemapDurand(gamma=1.3)
|
|
||||||
res_robertson = tonemap2.process(hdr_robertson.copy())
|
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
### 4. Merge exposures using Mertens fusion
|
### 4. Merge exposures using Mertens fusion
|
||||||
@ -173,5 +171,5 @@ Additional Resources
|
|||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
1. Try all tonemap algorithms: cv::TonemapDrago, cv::TonemapDurand, cv::TonemapMantiuk and cv::TonemapReinhard
|
1. Try all tonemap algorithms: cv::TonemapDrago, cv::TonemapMantiuk and cv::TonemapReinhard
|
||||||
2. Try changing the parameters in the HDR calibration and tonemap methods.
|
2. Try changing the parameters in the HDR calibration and tonemap methods.
|
||||||
|
@ -171,7 +171,7 @@ Now it's time to look at the results. Note that HDR image can't be stored in one
|
|||||||
formats, so we save it to Radiance image (.hdr). Also all HDR imaging functions return results in
|
formats, so we save it to Radiance image (.hdr). Also all HDR imaging functions return results in
|
||||||
[0, 1] range so we should multiply result by 255.
|
[0, 1] range so we should multiply result by 255.
|
||||||
|
|
||||||
You can try other tonemap algorithms: cv::TonemapDrago, cv::TonemapDurand, cv::TonemapMantiuk and cv::TonemapReinhard
|
You can try other tonemap algorithms: cv::TonemapDrago, cv::TonemapMantiuk and cv::TonemapReinhard
|
||||||
You can also adjust the parameters in the HDR calibration and tonemap methods for your own photos.
|
You can also adjust the parameters in the HDR calibration and tonemap methods for your own photos.
|
||||||
|
|
||||||
Results
|
Results
|
||||||
|
@ -376,43 +376,6 @@ results, default value is 0.85.
|
|||||||
*/
|
*/
|
||||||
CV_EXPORTS_W Ptr<TonemapDrago> createTonemapDrago(float gamma = 1.0f, float saturation = 1.0f, float bias = 0.85f);
|
CV_EXPORTS_W Ptr<TonemapDrago> createTonemapDrago(float gamma = 1.0f, float saturation = 1.0f, float bias = 0.85f);
|
||||||
|
|
||||||
/** @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 ocvTonemapDrago.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@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);
|
|
||||||
|
|
||||||
/** @brief This is a global tonemapping operator that models human visual system.
|
/** @brief This is a global tonemapping operator that models human visual system.
|
||||||
|
|
||||||
|
@ -193,94 +193,6 @@ Ptr<TonemapDrago> createTonemapDrago(float gamma, float saturation, float bias)
|
|||||||
return makePtr<TonemapDragoImpl>(gamma, saturation, bias);
|
return makePtr<TonemapDragoImpl>(gamma, saturation, bias);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_INSTRUMENT_REGION();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TonemapReinhardImpl CV_FINAL : public TonemapReinhard
|
class TonemapReinhardImpl CV_FINAL : public TonemapReinhard
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -105,12 +105,6 @@ TEST(Photo_Tonemap, regression)
|
|||||||
result.convertTo(result, CV_8UC3, 255);
|
result.convertTo(result, CV_8UC3, 255);
|
||||||
checkEqual(result, expected, 3, "Drago");
|
checkEqual(result, expected, 3, "Drago");
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
Ptr<TonemapReinhard> reinhard = createTonemapReinhard(gamma);
|
Ptr<TonemapReinhard> reinhard = createTonemapReinhard(gamma);
|
||||||
reinhard->process(img, result);
|
reinhard->process(img, result);
|
||||||
loadImage(test_path + "reinhard.png", expected);
|
loadImage(test_path + "reinhard.png", expected);
|
||||||
|
@ -35,7 +35,7 @@ int main(int argc, char**argv)
|
|||||||
|
|
||||||
//! [Tonemap HDR image]
|
//! [Tonemap HDR image]
|
||||||
Mat ldr;
|
Mat ldr;
|
||||||
Ptr<TonemapDurand> tonemap = createTonemapDurand(2.2f);
|
Ptr<Tonemap> tonemap = createTonemap(2.2f);
|
||||||
tonemap->process(hdr, ldr);
|
tonemap->process(hdr, ldr);
|
||||||
//! [Tonemap HDR image]
|
//! [Tonemap HDR image]
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import org.opencv.photo.CalibrateDebevec;
|
|||||||
import org.opencv.photo.MergeDebevec;
|
import org.opencv.photo.MergeDebevec;
|
||||||
import org.opencv.photo.MergeMertens;
|
import org.opencv.photo.MergeMertens;
|
||||||
import org.opencv.photo.Photo;
|
import org.opencv.photo.Photo;
|
||||||
import org.opencv.photo.TonemapDurand;
|
import org.opencv.photo.Tonemap;
|
||||||
|
|
||||||
class HDRImaging {
|
class HDRImaging {
|
||||||
public void loadExposureSeq(String path, List<Mat> images, List<Float> times) {
|
public void loadExposureSeq(String path, List<Mat> images, List<Float> times) {
|
||||||
@ -71,7 +71,7 @@ class HDRImaging {
|
|||||||
|
|
||||||
//! [Tonemap HDR image]
|
//! [Tonemap HDR image]
|
||||||
Mat ldr = new Mat();
|
Mat ldr = new Mat();
|
||||||
TonemapDurand tonemap = Photo.createTonemapDurand(2.2f, 4.0f, 1.0f, 2.0f, 2.0f);
|
Tonemap tonemap = Photo.createTonemap(2.2f);
|
||||||
tonemap.process(hdr, ldr);
|
tonemap.process(hdr, ldr);
|
||||||
//! [Tonemap HDR image]
|
//! [Tonemap HDR image]
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ hdr = merge_debevec.process(images, times, response)
|
|||||||
## [Make HDR image]
|
## [Make HDR image]
|
||||||
|
|
||||||
## [Tonemap HDR image]
|
## [Tonemap HDR image]
|
||||||
tonemap = cv.createTonemapDurand(2.2)
|
tonemap = cv.createTonemap(2.2)
|
||||||
ldr = tonemap.process(hdr)
|
ldr = tonemap.process(hdr)
|
||||||
## [Tonemap HDR image]
|
## [Tonemap HDR image]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user