Merge pull request #27396 from abhishek-gola:hdr_bug_fix

Fix NaNs in HDR Triangle Weights and Tonemapping and Update LDR Ground Truth in tutorial #27396

The PR closes #27392 

Updated the triangle weights to use a small epsilon value instead of zero to prevent NaN issues in HDR processing.
Also fixed a float-to-double division issue by explicitly casting double values to float, which was previously producing garbage values and leading to NaNs in tonemapping.

The current LDR ground truth image used in the tutorial [ldr.png](https://github.com/opencv/opencv/blob/4.x/doc/tutorials/others/images/ldr.png) was originally generated using TonemapDurand (check this commit 833f8d16fa), which was moved to opencv_contrib a long time ago in this commit: 742f22c09b. However, the current Tonemap implementation in OpenCV main only performs normalization and gamma correction, which produces noticeably different results. This PR updates the LDR grouth truth image in tutorial with the result of TonemapDrago, and tutorials to use TonemapDrago as Tonemap gives a darker image.

Tonemap output:
![ldr2](https://github.com/user-attachments/assets/e4f0cb97-ee4f-47b9-8962-2020ff211fd5)

TonemapDrago output:
![ldr](https://github.com/user-attachments/assets/4a898101-22bd-49e5-8db0-9e1062974ba3)


### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Abhishek Gola 2025-06-05 11:32:58 +05:30 committed by GitHub
parent 9e18169959
commit aef6ae4872
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 21 additions and 13 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

After

Width:  |  Height:  |  Size: 535 KiB

View File

@ -65,10 +65,14 @@ Mat triangleWeights()
Mat w(LDR_SIZE, 1, CV_32F);
int half = LDR_SIZE / 2;
int maxVal = LDR_SIZE - 1;
for (int i = 0; i < LDR_SIZE; i++)
float epsilon = 1e-6f;
w.at<float>(0) = epsilon;
w.at<float>(LDR_SIZE-1) = epsilon;
for (int i = 1; i < LDR_SIZE-1; i++){
w.at<float>(i) = (i < half)
? static_cast<float>(i)
: static_cast<float>(maxVal - i);
}
return w;
}

View File

@ -72,8 +72,10 @@ public:
double min, max;
minMaxLoc(src, &min, &max);
float fmin = static_cast<float>(min);
float fmax = static_cast<float>(max);
if(max - min > DBL_EPSILON) {
dst = (src - min) / (max - min);
dst = (src - fmin) / (fmax - fmin);
} else {
src.copyTo(dst);
}
@ -139,8 +141,9 @@ public:
gray_img /= mean;
log_img.release();
double max;
minMaxLoc(gray_img, NULL, &max);
double dmax;
minMaxLoc(gray_img, NULL, &dmax);
float max = static_cast<float>(dmax);
CV_Assert(max > 0);
Mat map;
@ -150,7 +153,6 @@ public:
log(2.0f + 8.0f * div, div);
map = map.mul(1.0f / div);
div.release();
mapLuminance(img, img, gray_img, map, saturation);
linear->setGamma(gamma);
@ -223,12 +225,14 @@ public:
log_(gray_img, log_img);
float log_mean = static_cast<float>(sum(log_img)[0] / log_img.total());
double log_min, log_max;
minMaxLoc(log_img, &log_min, &log_max);
double dlog_min, dlog_max;
minMaxLoc(log_img, &dlog_min, &dlog_max);
float log_max = static_cast<float>(dlog_max);
float log_min = static_cast<float>(dlog_min);
log_img.release();
double key = static_cast<float>((log_max - log_mean) / (log_max - log_min));
float map_key = 0.3f + 0.7f * pow(static_cast<float>(key), 1.4f);
float key = (log_max - log_mean) / (log_max - log_min);
float map_key = 0.3f + 0.7f * pow(key, 1.4f);
intensity = exp(-intensity);
Scalar chan_mean = mean(img);
float gray_mean = static_cast<float>(mean(gray_img)[0]);
@ -287,9 +291,9 @@ protected:
float gamma, intensity, light_adapt, color_adapt;
};
Ptr<TonemapReinhard> createTonemapReinhard(float gamma, float contrast, float sigma_color, float sigma_space)
Ptr<TonemapReinhard> createTonemapReinhard(float gamma, float intensity, float light_adapt, float color_adapt)
{
return makePtr<TonemapReinhardImpl>(gamma, contrast, sigma_color, sigma_space);
return makePtr<TonemapReinhardImpl>(gamma, intensity, light_adapt, color_adapt);
}
class TonemapMantiukImpl CV_FINAL : public TonemapMantiuk

View File

@ -35,7 +35,7 @@ int main(int argc, char**argv)
//! [Tonemap HDR image]
Mat ldr;
Ptr<Tonemap> tonemap = createTonemap(2.2f);
Ptr<TonemapDrago> tonemap = createTonemapDrago(2.2f);
tonemap->process(hdr, ldr);
//! [Tonemap HDR image]

View File

@ -40,7 +40,7 @@ hdr = merge_debevec.process(images, times, response)
## [Make HDR image]
## [Tonemap HDR image]
tonemap = cv.createTonemap(2.2)
tonemap = cv.createTonemapDrago(2.2)
ldr = tonemap.process(hdr)
## [Tonemap HDR image]