diff --git a/modules/imgproc/src/contours_new.cpp b/modules/imgproc/src/contours_new.cpp index 355a5e349c..b87a06255d 100644 --- a/modules/imgproc/src/contours_new.cpp +++ b/modules/imgproc/src/contours_new.cpp @@ -700,7 +700,10 @@ void cv::findContours(InputArray _image, // preprocess Mat image; - copyMakeBorder(_image, image, 1, 1, 1, 1, BORDER_CONSTANT | BORDER_ISOLATED, Scalar(0)); + if (_image.empty()) + image = Mat::zeros(2, 2, _image.type()); + else + copyMakeBorder(_image, image, 1, 1, 1, 1, BORDER_CONSTANT | BORDER_ISOLATED, Scalar(0)); if (image.type() != CV_32SC1) threshold(image, image, 0, 1, THRESH_BINARY); diff --git a/modules/imgproc/src/contours_truco.cpp b/modules/imgproc/src/contours_truco.cpp index d2bd0c74ea..53012289a4 100644 --- a/modules/imgproc/src/contours_truco.cpp +++ b/modules/imgproc/src/contours_truco.cpp @@ -648,6 +648,11 @@ void findTRUContours(InputArray _src, OutputArrayOfArrays _contours, int minSize CV_INSTRUMENT_REGION(); Mat src = _src.getMat(); CV_Assert(src.type() == CV_8UC1); + if (src.empty()) + { + _contours.clear(); + return; + } // Buffer handling cv::Mat padded; diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp index 1cf8e327c7..6915e92e14 100644 --- a/modules/imgproc/test/test_contours.cpp +++ b/modules/imgproc/test/test_contours.cpp @@ -125,6 +125,35 @@ TEST(Imgproc_FindContours, border) ASSERT_EQ(0, cvtest::norm(img, img_draw_contours, NORM_INF)); } +TEST(Imgproc_FindContours, empty_input) +{ + Mat empty; + std::vector > contours(1, std::vector(1, Point(1, 2))); + std::vector hierarchy(1, Vec4i(0, 0, 0, 0)); + + // General path (with hierarchy) + findContours(empty, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); + EXPECT_TRUE(contours.empty()); + EXPECT_TRUE(hierarchy.empty()); + + // Fast path (RETR_LIST without hierarchy -> findTRUContours) + contours.assign(1, std::vector(1, Point(1, 2))); + findContours(empty, contours, RETR_LIST, CHAIN_APPROX_SIMPLE, Point(3, 4)); + EXPECT_TRUE(contours.empty()); + + // RETR_FLOODFILL with empty CV_32SC1 + Mat empty32s(0, 0, CV_32SC1); + contours.assign(1, std::vector(1, Point(1, 2))); + hierarchy.assign(1, Vec4i(0, 0, 0, 0)); + findContours(empty32s, contours, hierarchy, RETR_FLOODFILL, CHAIN_APPROX_SIMPLE); + EXPECT_TRUE(contours.empty()); + EXPECT_TRUE(hierarchy.empty()); + + // Empty input still goes through type/mode validation + EXPECT_THROW(findContours(Mat(0, 0, CV_32FC1), contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE), cv::Exception); + EXPECT_THROW(findContours(empty, contours, hierarchy, RETR_FLOODFILL, CHAIN_APPROX_SIMPLE), cv::Exception); +} + TEST(Imgproc_FindContours, regression_4363_shared_nbd) { // Create specific test image