diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index fe16ee78ee..4007031b2f 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -3580,6 +3580,8 @@ public: Mat cross(const Mat& m) const; double dot(const Mat& m) const; + void swap(MatExpr& b); + const MatOp* op; int flags; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 55b4e625be..9b7df87d8b 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -150,9 +150,6 @@ _InputArray::_InputArray(const Mat_<_Tp>& m) inline _InputArray::_InputArray(const double& val) { init(FIXED_TYPE + FIXED_SIZE + MATX + CV_64F + ACCESS_READ, &val, Size(1,1)); } -inline _InputArray::_InputArray(const MatExpr& expr) -{ init(FIXED_TYPE + FIXED_SIZE + EXPR + ACCESS_READ, &expr); } - inline _InputArray::_InputArray(const cuda::GpuMat& d_mat) { init(CUDA_GPU_MAT + ACCESS_READ, &d_mat); } @@ -4054,6 +4051,9 @@ inline void UMatData::markDeviceCopyObsolete(bool flag) //! @endcond +static inline +void swap(MatExpr& a, MatExpr& b) { a.swap(b); } + } //cv #ifdef _MSC_VER diff --git a/modules/core/src/matrix_expressions.cpp b/modules/core/src/matrix_expressions.cpp index 57beb68e71..d4f8b743cf 100644 --- a/modules/core/src/matrix_expressions.cpp +++ b/modules/core/src/matrix_expressions.cpp @@ -1821,4 +1821,37 @@ MatExpr Mat::eye(Size size, int type) return e; } +void MatExpr::swap(MatExpr& other) +{ + using std::swap; + + swap(op, other.op); + swap(flags, other.flags); + + swap(a, other.a); + swap(b, other.b); + swap(c, other.c); + + swap(alpha, other.alpha); + swap(beta, other.beta); + + swap(s, other.s); +} + +_InputArray::_InputArray(const MatExpr& expr) +{ +#if 1 + if (!isIdentity(expr)) + { + Mat result = expr; // TODO improve through refcount == 1 of expr.a (inplace operation is possible - except gemm?) + MatExpr result_expr(result); + swap(const_cast(expr), result_expr); + } + CV_Assert(isIdentity(expr)); + init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_READ, &expr.a); +#else + init(FIXED_TYPE + FIXED_SIZE + EXPR + ACCESS_READ, &expr); +#endif +} + } // cv:: diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index efb433dc79..58eafd0748 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1969,6 +1969,21 @@ TEST(Core_InputArray, support_CustomType) } } + +TEST(Core_InputArray, fetch_MatExpr) +{ + Mat a(Size(10, 5), CV_32FC1, 5); + Mat b(Size(10, 5), CV_32FC1, 2); + MatExpr expr = a * b.t(); // gemm expression + Mat dst; + cv::add(expr, Scalar(1), dst); // invoke gemm() here + void* expr_data = expr.a.data; + Mat result = expr; // should not call gemm() here again + EXPECT_EQ(expr_data, result.data); // expr data is reused + EXPECT_EQ(dst.size(), result.size()); +} + + TEST(Core_Vectors, issue_13078) { float floats_[] = { 1, 2, 3, 4, 5, 6, 7, 8 };