diff --git a/modules/geometry/src/geometry.cpp b/modules/geometry/src/geometry.cpp index 5cba72c35d..c9073c2aa2 100644 --- a/modules/geometry/src/geometry.cpp +++ b/modules/geometry/src/geometry.cpp @@ -504,7 +504,7 @@ double arcLength( InputArray _curve, bool is_closed ) static Rect maskBoundingRect( const Mat& img ) { - CV_Assert( img.depth() <= CV_8S && img.channels() == 1 ); + CV_Assert( (img.depth() <= CV_8S || img.depth() == CV_Bool) && img.channels() == 1 ); Size size = img.size(); int xmin = size.width, ymin = -1, xmax = -1, ymax = -1, i, j, k; @@ -709,7 +709,10 @@ cv::Rect boundingRect(InputArray array) CV_INSTRUMENT_REGION(); Mat m = array.getMat(); - return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m); + // CV_Bool is a 1-byte mask type (added in 5.0); route it through the + // byte-wise mask path, same as CV_8U/CV_8S. See #29578. + int depth = m.depth(); + return (depth <= CV_8U || depth == CV_Bool) ? maskBoundingRect(m) : pointSetBoundingRect(m); } cv::Matx23d getRotationMatrix2D_(Point2f center, double angle, double scale) diff --git a/modules/geometry/test/test_boundingrect.cpp b/modules/geometry/test/test_boundingrect.cpp index cf70b66e04..0bc8e55b7d 100644 --- a/modules/geometry/test/test_boundingrect.cpp +++ b/modules/geometry/test/test_boundingrect.cpp @@ -96,4 +96,31 @@ TEST(Imgproc_BoundingRect, bug_24217) } } +// See https://github.com/opencv/opencv/issues/29578 +// cv::Mat_::depth() returns CV_Bool in 5.0, which regressed boundingRect +// (it used to be treated as CV_8U in 4.x). A boolean mask must be handled as a +// byte-wise mask, matching the CV_8UC1 result. +TEST(Imgproc_BoundingRect, bool_mask_29578) +{ + for (int image_width = 3; image_width < 20; image_width++) + { + for (int image_height = 1; image_height < 15; image_height++) + { + cv::Rect rect(0, image_height - 1, 3, 1); + + cv::Mat_ mask(cv::Size(image_width, image_height), false); + mask(rect).setTo(true); + + cv::Mat_ ref(cv::Size(image_width, image_height), (uchar)0); + ref(rect).setTo(255); + + EXPECT_EQ(mask.depth(), CV_Bool); + cv::Rect result; + ASSERT_NO_THROW(result = boundingRect(mask)); + EXPECT_EQ(result, rect); + EXPECT_EQ(result, boundingRect(ref)); + } + } +} + }} // namespace