diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index 4058856fff..00194b628f 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -1562,10 +1562,12 @@ void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst, bool src1Scalar = checkScalar(src1, _src2.type(), kind1, kind2); bool src2Scalar = checkScalar(src2, _src1.type(), kind2, kind1); - if (!src1Scalar && !src2Scalar && mask.empty() && - src1.depth() == CV_8U && src2.depth() == CV_8U) + if (!src1Scalar && !src2Scalar && + src1.depth() == CV_8U && src2.type() == src1.type() && + src1.dims == 2 && src2.size() == src1.size() && + mask.empty()) { - if (dtype == -1) + if (dtype < 0) { if (_dst.fixedType()) { @@ -1577,11 +1579,11 @@ void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst, } } - dtype = CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), _src1.channels()); + dtype = CV_MAT_DEPTH(dtype); - if (dtype == _dst.type()) + if (!_dst.fixedType() || dtype == _dst.depth()) { - _dst.create(_src1.size(), dtype); + _dst.create(src1.size(), CV_MAKE_TYPE(dtype, src1.channels())); if (dtype == CV_16S) { diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 68b06267b2..f3faa57fce 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -1580,21 +1580,215 @@ TEST_P(Mul1, One) INSTANTIATE_TEST_CASE_P(Arithm, Mul1, testing::Values(Size(2, 2), Size(1, 1))); -TEST(Subtract, EmptyOutputMat) +class SubtractOutputMatNotEmpty : public testing::TestWithParam< std::tr1::tuple > { - cv::Mat src1 = cv::Mat::zeros(16, 16, CV_8UC1); - cv::Mat src2 = cv::Mat::zeros(16, 16, CV_8UC1); - cv::Mat dst1, dst2, dst3; +public: + cv::Size size; + int src_type; + int dst_depth; + bool fixed; - cv::subtract(src1, src2, dst1, cv::noArray(), CV_16S); - cv::subtract(src1, src2, dst2); - cv::subtract(src1, cv::Scalar::all(0), dst3, cv::noArray(), CV_16S); + void SetUp() + { + size = std::tr1::get<0>(GetParam()); + src_type = std::tr1::get<1>(GetParam()); + dst_depth = std::tr1::get<2>(GetParam()); + fixed = std::tr1::get<3>(GetParam()); + } +}; - ASSERT_FALSE(dst1.empty()); - ASSERT_FALSE(dst2.empty()); - ASSERT_FALSE(dst3.empty()); +TEST_P(SubtractOutputMatNotEmpty, Mat_Mat) +{ + cv::Mat src1(size, src_type, cv::Scalar::all(16)); + cv::Mat src2(size, src_type, cv::Scalar::all(16)); - ASSERT_EQ(0, cv::countNonZero(dst1)); - ASSERT_EQ(0, cv::countNonZero(dst2)); - ASSERT_EQ(0, cv::countNonZero(dst3)); + cv::Mat dst; + + if (!fixed) + { + cv::subtract(src1, src2, dst, cv::noArray(), dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels())); + cv::subtract(src1, src2, fixed_dst, cv::noArray(), dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src1.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); } + +TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_WithMask) +{ + cv::Mat src1(size, src_type, cv::Scalar::all(16)); + cv::Mat src2(size, src_type, cv::Scalar::all(16)); + cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(src1, src2, dst, mask, dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels())); + cv::subtract(src1, src2, fixed_dst, mask, dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src1.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_Expr) +{ + cv::Mat src1(size, src_type, cv::Scalar::all(16)); + cv::Mat src2(size, src_type, cv::Scalar::all(16)); + + cv::Mat dst = src1 - src2; + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src1.size(), dst.size()); + ASSERT_EQ(src1.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Mat_Scalar) +{ + cv::Mat src(size, src_type, cv::Scalar::all(16)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(src, cv::Scalar::all(16), dst, cv::noArray(), dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels())); + cv::subtract(src, cv::Scalar::all(16), fixed_dst, cv::noArray(), dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Mat_Scalar_WithMask) +{ + cv::Mat src(size, src_type, cv::Scalar::all(16)); + cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(src, cv::Scalar::all(16), dst, mask, dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels())); + cv::subtract(src, cv::Scalar::all(16), fixed_dst, mask, dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Scalar_Mat) +{ + cv::Mat src(size, src_type, cv::Scalar::all(16)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(cv::Scalar::all(16), src, dst, cv::noArray(), dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels())); + cv::subtract(cv::Scalar::all(16), src, fixed_dst, cv::noArray(), dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Scalar_Mat_WithMask) +{ + cv::Mat src(size, src_type, cv::Scalar::all(16)); + cv::Mat mask(size, CV_8UC1, cv::Scalar::all(255)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(cv::Scalar::all(16), src, dst, mask, dst_depth); + } + else + { + const cv::Mat fixed_dst(size, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src.channels())); + cv::subtract(cv::Scalar::all(16), src, fixed_dst, mask, dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src.size(), dst.size()); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +TEST_P(SubtractOutputMatNotEmpty, Mat_Mat_3d) +{ + int dims[] = {5, size.height, size.width}; + + cv::Mat src1(3, dims, src_type, cv::Scalar::all(16)); + cv::Mat src2(3, dims, src_type, cv::Scalar::all(16)); + + cv::Mat dst; + + if (!fixed) + { + cv::subtract(src1, src2, dst, cv::noArray(), dst_depth); + } + else + { + const cv::Mat fixed_dst(3, dims, CV_MAKE_TYPE((dst_depth > 0 ? dst_depth : CV_16S), src1.channels())); + cv::subtract(src1, src2, fixed_dst, cv::noArray(), dst_depth); + dst = fixed_dst; + dst_depth = fixed_dst.depth(); + } + + ASSERT_FALSE(dst.empty()); + ASSERT_EQ(src1.dims, dst.dims); + ASSERT_EQ(src1.size, dst.size); + ASSERT_EQ(dst_depth > 0 ? dst_depth : src1.depth(), dst.depth()); + ASSERT_EQ(0, cv::countNonZero(dst.reshape(1))); +} + +INSTANTIATE_TEST_CASE_P(Arithm, SubtractOutputMatNotEmpty, testing::Combine( + testing::Values(cv::Size(16, 16), cv::Size(13, 13), cv::Size(16, 13), cv::Size(13, 16)), + testing::Values(perf::MatType(CV_8UC1), CV_8UC3, CV_8UC4, CV_16SC1, CV_16SC3), + testing::Values(-1, CV_16S, CV_32S, CV_32F), + testing::Bool()));