From c3fe92d813ca17a523559ed09ab3bd19b0b6d4b3 Mon Sep 17 00:00:00 2001 From: Gursimar Singh Date: Wed, 21 May 2025 11:10:11 +0530 Subject: [PATCH] Merge pull request #27270 from gursimarsingh:bug_fix_unstable_crf Bug fix unstable crf #27270 ### 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 The PR resolves the issue for triangle Weights used by debevec algorithm being non zero at extremes. It resolves #24966 The fix needs ground truth data to be changed in order to pass existing tests. PR to opencv_extra: https://github.com/opencv/opencv_extra/pull/1253 --- modules/photo/src/hdr_common.cpp | 10 ++++--- modules/photo/test/test_hdr.cpp | 49 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/modules/photo/src/hdr_common.cpp b/modules/photo/src/hdr_common.cpp index 983efe3792..5e4bea9d85 100644 --- a/modules/photo/src/hdr_common.cpp +++ b/modules/photo/src/hdr_common.cpp @@ -63,10 +63,12 @@ Mat triangleWeights() { // hat function Mat w(LDR_SIZE, 1, CV_32F); - int half = LDR_SIZE / 2; - for(int i = 0; i < LDR_SIZE; i++) { - w.at(i) = i < half ? i + 1.0f : LDR_SIZE - i; - } + int half = LDR_SIZE / 2; + int maxVal = LDR_SIZE - 1; + for (int i = 0; i < LDR_SIZE; i++) + w.at(i) = (i < half) + ? static_cast(i) + : static_cast(maxVal - i); return w; } diff --git a/modules/photo/test/test_hdr.cpp b/modules/photo/test/test_hdr.cpp index a26e83e49e..264a7d7257 100644 --- a/modules/photo/test/test_hdr.cpp +++ b/modules/photo/test/test_hdr.cpp @@ -187,11 +187,9 @@ TEST(Photo_MergeDebevec, regression) Mat result, expected; loadImage(test_path + "merge/debevec.hdr", expected); merge->process(images, result, times, response); - Ptr map = createTonemap(); map->process(result, result); map->process(expected, expected); - checkEqual(expected, result, 1e-2f, "Debevec"); } @@ -221,16 +219,15 @@ TEST(Photo_CalibrateDebevec, regression) loadExposureSeq(test_path + "exposures/", images, times); loadResponseCSV(test_path + "calibrate/debevec.csv", expected); Ptr calibrate = createCalibrateDebevec(); - calibrate->process(images, response, times); Mat diff = abs(response - expected); diff = diff.mul(1.0f / response); double max; minMaxLoc(diff, NULL, &max); #if defined(__arm__) || defined(__aarch64__) - ASSERT_LT(max, 0.2); + ASSERT_LT(max, 0.25); #else - ASSERT_LT(max, 0.1); + ASSERT_LT(max, 0.15); #endif } @@ -266,4 +263,46 @@ TEST(Photo_CalibrateRobertson, bug_18180) EXPECT_EQ(0.0, cv::norm(response, response_no_nans, NORM_L2)); } +TEST(Photo_CalibrateDebevec, bug_24966) +{ + string test_path = string(cvtest::TS::ptr()->get_data_path()) + "hdr/"; + vector all_images; + vector all_times; + loadExposureSeq(test_path + "exposures/", all_images, all_times); + // Use a balanced subset of exposures + vector selected_indices = {1,2,3,4,5}; + vector images; + vector times; + for (int idx : selected_indices) { + images.push_back(all_images[idx]); + times.push_back(all_times[idx]); + } + // Run CRF estimation for different sample points + vector sample_points = {200,300,400}; + vector responses; + for (int samples : sample_points) { + Ptr calibrate = createCalibrateDebevec(samples); + Mat response; + calibrate->process(images, response, times); + Mat roi = response.rowRange(15, 240); //Checking CRF only in the middle of the image + responses.push_back(roi); + } + + // Compare consecutive pairs of CRFs + for (size_t i = 0; i < responses.size()-1; ++i) { + Mat diff = abs(responses[i] - responses[i+1]); + double max_diff; + minMaxLoc(diff, nullptr, &max_diff); + cout << "max_diff = " << max_diff << endl; + #if defined(__aarch64__) && defined(__APPLE__) + ASSERT_LT(max_diff, 10) << "CRF instability detected between samples=" + << sample_points[i] << " and " << sample_points[i+1] + << " (max diff = " << max_diff << ")"; + #else + ASSERT_LT(max_diff, 5) << "CRF instability detected between samples=" + << sample_points[i] << " and " << sample_points[i+1] + << " (max diff = " << max_diff << ")"; + #endif + } +} }} // namespace