From eb04b2bfa92debc6be2ca534b7d373c00c331e3c Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Thu, 15 Dec 2016 09:16:40 -0600 Subject: [PATCH] Added N-dim submat selection with vectors Currently, to select a submatrix of a N-dimensional matrix, it requires two lines of code while only one line of code is required if using a 2D array. I added functionality to be able to select an N-dim submatrix using a vector list instead of a Range pointer. This allows initializer lists to be used for a one-line selection. --- modules/core/include/opencv2/core/mat.hpp | 20 +++++++++++++++ modules/core/include/opencv2/core/mat.inl.hpp | 23 +++++++++++++++++ modules/core/src/matrix.cpp | 25 +++++++++++++++++++ modules/core/src/umatrix.cpp | 25 +++++++++++++++++++ modules/core/test/test_mat.cpp | 25 +++++++++++++++++++ 5 files changed, 118 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index c2b4558db5..39c197ea3a 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -925,6 +925,16 @@ public: */ Mat(const Mat& m, const Range* ranges); + /** @overload + @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied + by these constructors. Instead, the header pointing to m data or its sub-array is constructed and + associated with it. The reference counter, if any, is incremented. So, when you modify the matrix + formed using such a constructor, you also modify the corresponding elements of m . If you want to + have an independent copy of the sub-array, use Mat::clone() . + @param ranges Array of selected ranges of m along each dimensionality. + */ + Mat(const Mat& m, const std::vector& ranges); + /** @overload @param vec STL vector whose elements form the matrix. The matrix has a single column and the number of rows equal to the number of vector elements. Type of the matrix matches the type of vector @@ -1516,6 +1526,11 @@ public: */ Mat operator()( const Range* ranges ) const; + /** @overload + @param ranges Array of selected ranges along each array dimension. + */ + Mat operator()(const std::vector& ranges) const; + // //! converts header to CvMat; no data is copied // operator CvMat() const; // //! converts header to CvMatND; no data is copied @@ -2054,6 +2069,8 @@ public: Mat_(const Mat_& m, const Rect& roi); //! selects a submatrix, n-dim version Mat_(const Mat_& m, const Range* ranges); + //! selects a submatrix, n-dim version + Mat_(const Mat_& m, const std::vector& ranges); //! from a matrix expression explicit Mat_(const MatExpr& e); //! makes a matrix out of Vec, std::vector, Point_ or Point3_. The matrix will have a single column @@ -2123,6 +2140,7 @@ public: Mat_ operator()( const Range& rowRange, const Range& colRange ) const; Mat_ operator()( const Rect& roi ) const; Mat_ operator()( const Range* ranges ) const; + Mat_ operator()(const std::vector& ranges) const; //! more convenient forms of row and element access operators _Tp* operator [](int y); @@ -2227,6 +2245,7 @@ public: UMat(const UMat& m, const Range& rowRange, const Range& colRange=Range::all()); UMat(const UMat& m, const Rect& roi); UMat(const UMat& m, const Range* ranges); + UMat(const UMat& m, const std::vector& ranges); //! builds matrix from std::vector with or without copying the data template explicit UMat(const std::vector<_Tp>& vec, bool copyData=false); //! builds matrix from cv::Vec; the data is copied by default @@ -2333,6 +2352,7 @@ public: UMat operator()( Range rowRange, Range colRange ) const; UMat operator()( const Rect& roi ) const; UMat operator()( const Range* ranges ) const; + UMat operator()(const std::vector& ranges) const; //! returns true iff the matrix data is continuous // (i.e. when there are no gaps between successive rows). diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index d164ac68c8..4a32de165a 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -736,6 +736,12 @@ Mat Mat::operator()(const Range* ranges) const return Mat(*this, ranges); } +inline +Mat Mat::operator()(const std::vector& ranges) const +{ + return Mat(*this, ranges); +} + inline bool Mat::isContinuous() const { @@ -1383,6 +1389,11 @@ Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges) : Mat(m, ranges) {} +template inline +Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const std::vector& ranges) + : Mat(m, ranges) +{} + template inline Mat_<_Tp>::Mat_(const Mat& m) : Mat() @@ -1614,6 +1625,12 @@ Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const return Mat_<_Tp>(*this, ranges); } +template inline +Mat_<_Tp> Mat_<_Tp>::operator()(const std::vector& ranges) const +{ + return Mat_<_Tp>(*this, ranges); +} + template inline _Tp* Mat_<_Tp>::operator [](int y) { @@ -3540,6 +3557,12 @@ UMat UMat::operator()(const Range* ranges) const return UMat(*this, ranges); } +inline +UMat UMat::operator()(const std::vector& ranges) const +{ + return UMat(*this, ranges); +} + inline bool UMat::isContinuous() const { diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index d1383af8e8..1590fab485 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -583,6 +583,31 @@ Mat::Mat(const Mat& m, const Range* ranges) updateContinuityFlag(*this); } +Mat::Mat(const Mat& m, const std::vector& ranges) + : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0), + datalimit(0), allocator(0), u(0), size(&rows) +{ + int d = m.dims; + + CV_Assert((int)ranges.size() == d); + for (int i = 0; i < d; i++) + { + Range r = ranges[i]; + CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i])); + } + *this = m; + for (int i = 0; i < d; i++) + { + Range r = ranges[i]; + if (r != Range::all() && r != Range(0, size.p[i])) + { + size.p[i] = r.end - r.start; + data += r.start*step.p[i]; + flags |= SUBMATRIX_FLAG; + } + } + updateContinuityFlag(*this); +} static Mat cvMatNDToMat(const CvMatND* m, bool copyData) { diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index a543595b8b..5874be82d3 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -512,6 +512,31 @@ UMat::UMat(const UMat& m, const Range* ranges) updateContinuityFlag(*this); } +UMat::UMat(const UMat& m, const std::vector& ranges) + : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows) +{ + int i, d = m.dims; + + CV_Assert((int)ranges.size() == d); + for (i = 0; i < d; i++) + { + Range r = ranges[i]; + CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i])); + } + *this = m; + for (i = 0; i < d; i++) + { + Range r = ranges[i]; + if (r != Range::all() && r != Range(0, size.p[i])) + { + size.p[i] = r.end - r.start; + offset += r.start*step.p[i]; + flags |= SUBMATRIX_FLAG; + } + } + updateContinuityFlag(*this); +} + UMat UMat::diag(int d) const { CV_Assert( dims <= 2 ); diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index fa744f194e..9a379f468d 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1546,3 +1546,28 @@ TEST(Mat, regression_5917_clone_empty) ASSERT_NO_THROW(cloned = source.clone()); } + +TEST(Mat, regression_7873_mat_vector_initialize) +{ + std::vector dims; + dims.push_back(12); + dims.push_back(3); + dims.push_back(2); + Mat multi_mat(dims, CV_32FC1, cv::Scalar(0)); + + ASSERT_EQ(3, multi_mat.dims); + ASSERT_EQ(12, multi_mat.size[0]); + ASSERT_EQ(3, multi_mat.size[1]); + ASSERT_EQ(2, multi_mat.size[2]); + + std::vector ranges; + ranges.push_back(Range(1, 2)); + ranges.push_back(Range::all()); + ranges.push_back(Range::all()); + Mat sub_mat = multi_mat(ranges); + + ASSERT_EQ(3, sub_mat.dims); + ASSERT_EQ(1, sub_mat.size[0]); + ASSERT_EQ(3, sub_mat.size[1]); + ASSERT_EQ(2, sub_mat.size[2]); +}