From 75598e5377af6edb6c080da6c2a4b437cc8f0675 Mon Sep 17 00:00:00 2001 From: Maxim Smolskiy Date: Wed, 8 Oct 2025 08:50:54 +0300 Subject: [PATCH] Merge pull request #27877 from MaximSmolskiy:fix_QRCodeDetector_detectAndDecode_crash Fix QRCodeDetector::detectAndDecode crash #27877 ### Pull Request Readiness Checklist Fix #27807 The problem is that when we find closest points from hull, we can get same closest point for several different points 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 - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake --- modules/objdetect/src/qrcode.cpp | 19 ++++++++++--------- modules/objdetect/test/test_qrcode.cpp | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp index 8391aabf62..f79829eb7c 100644 --- a/modules/objdetect/src/qrcode.cpp +++ b/modules/objdetect/src/qrcode.cpp @@ -772,21 +772,27 @@ vector QRDetect::getQuadrilateral(vector angle_list) const double experimental_area = fabs(contourArea(hull)); vector result_hull_point(angle_size); + vector used_hull_point(hull_size, false); double min_norm; for (size_t i = 0; i < angle_size; i++) { min_norm = std::numeric_limits::max(); - Point closest_pnt; + int closest_pnt_idx = -1; for (int j = 0; j < hull_size; j++) { + if (used_hull_point[j]) + { + continue; + } double temp_norm = norm(hull[j] - angle_list[i]); if (min_norm > temp_norm) { min_norm = temp_norm; - closest_pnt = hull[j]; + closest_pnt_idx = j; } } - result_hull_point[i] = closest_pnt; + result_hull_point[i] = hull[closest_pnt_idx]; + used_hull_point[closest_pnt_idx] = true; } int start_line[2] = { 0, 0 }, finish_line[2] = { 0, 0 }, unstable_pnt = 0; @@ -2958,12 +2964,7 @@ std::string ImplContour::decode(InputArray in, InputArray points, OutputArray st vector src_points; points.copyTo(src_points); CV_Assert(src_points.size() == 4); - if (contourArea(src_points) <= 0.0) - { - if (straight_qrcode.needed()) - straight_qrcode.release(); - return std::string(); - } + CV_CheckGT(contourArea(src_points), 0.0, "Invalid QR code source points"); QRDecode qrdec(useAlignmentMarkers); qrdec.init(inarr, src_points); diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp index 2912d39028..c49480d38f 100644 --- a/modules/objdetect/test/test_qrcode.cpp +++ b/modules/objdetect/test/test_qrcode.cpp @@ -470,7 +470,7 @@ TEST(Objdetect_QRCode_basic, not_found_qrcode) QRCodeDetector qrcode; EXPECT_FALSE(qrcode.detect(zero_image, corners)); corners = std::vector(4); - EXPECT_NO_THROW(qrcode.decode(zero_image, corners, straight_barcode)); + EXPECT_ANY_THROW(qrcode.decode(zero_image, corners, straight_barcode)); } TEST(Objdetect_QRCode_detect, detect_regression_21287)