From 64bbaa9f41be3e96a883cdbc11635eb84f18140c Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov <2536374+asmorkalov@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:00:17 +0300 Subject: [PATCH] Merge pull request #27972 from asmorkalov:as/dst_mat_type Force empty output type where it's defined in API #27972 The PR replaces: - https://github.com/opencv/opencv/pull/27936 - https://github.com/opencv/opencv/pull/21059 Empty matrix has undefined type, so user code should not relay on the output type, if it's empty. The PR introduces some exceptions: - copyTo documentation defines, that the method re-create output buffer and set it's type. - convertTo has output type as parameter and output type is defined and expected. --- modules/core/src/arithm.cpp | 12 ++++++++++++ modules/core/src/convert.dispatch.cpp | 2 ++ modules/core/src/copy.cpp | 1 + modules/core/src/umatrix.cpp | 1 + modules/core/test/test_mat.cpp | 9 +++++++++ modules/core/test/test_umat.cpp | 8 ++++++++ 6 files changed, 33 insertions(+) diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index 5c1033be81..ccb104cebe 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -1113,6 +1113,10 @@ void cv::add( InputArray src1, InputArray src2, OutputArray dst, if (src1.empty() && src2.empty()) { dst.release(); + if (dtype >= 0) + { + dst.create(0, 0, dtype); + } return; } @@ -1140,6 +1144,10 @@ void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst, if (_src1.empty() && _src2.empty()) { _dst.release(); + if (dtype >= 0) + { + _dst.create(0, 0, dtype); + } return; } @@ -1345,6 +1353,10 @@ void cv::addWeighted( InputArray src1, double alpha, InputArray src2, if (src1.empty() && src2.empty()) { dst.release(); + if (dtype >= 0) + { + dst.create(0, 0, dtype); + } return; } diff --git a/modules/core/src/convert.dispatch.cpp b/modules/core/src/convert.dispatch.cpp index a33708a557..0df033af6a 100644 --- a/modules/core/src/convert.dispatch.cpp +++ b/modules/core/src/convert.dispatch.cpp @@ -252,6 +252,7 @@ void Mat::convertTo(OutputArray dst, int type_, double alpha, double beta) const if (empty()) { dst.release(); + dst.create(size(), type_ >= 0 ? type_ : type()); return; } @@ -318,6 +319,7 @@ void UMat::convertTo(OutputArray dst, int type_, double alpha, double beta) cons if (empty()) { dst.release(); + dst.create(size(), type_ >= 0 ? type_ : type()); return; } diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 68d6b938e7..43f477aeae 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -447,6 +447,7 @@ void Mat::copyTo( OutputArray _dst ) const if( empty() ) { _dst.release(); + _dst.create(size(), type()); return; } diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index 65d50458dc..ceb4c064ec 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -1153,6 +1153,7 @@ void UMat::copyTo(OutputArray _dst) const if( empty() ) { _dst.release(); + _dst.create(size(), type()); return; } diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index ae8d5ddfda..9ba47755b4 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1385,6 +1385,15 @@ TEST(Core_Mat, push_back) } } +TEST(Core_Mat, copyToConvertTo_Empty) +{ + cv::Mat A(0, 0, CV_16SC2), B, C; + A.copyTo(B); + ASSERT_EQ(A.type(), B.type()); + A.convertTo(C, CV_32SC2); + ASSERT_EQ(C.type(), CV_32SC2); +} + TEST(Core_Mat, copyNx1ToVector) { cv::Mat_ src(5, 1); diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp index 34e6d2be75..a1fc434dc6 100644 --- a/modules/core/test/test_umat.cpp +++ b/modules/core/test/test_umat.cpp @@ -1199,6 +1199,14 @@ TEST(UMat, async_cleanup_without_call_chain_warning) } } +TEST(UMat, copyToConvertTo_Empty) +{ + cv::UMat A(0, 0, CV_16SC2), B, C; + A.copyTo(B); + ASSERT_EQ(A.type(), B.type()); + A.convertTo(C, CV_32SC2); + ASSERT_EQ(C.type(), CV_32SC2); +} ///////////// oclCleanupCallback threadsafe check (#5062) /////////////////////