diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 8161efc57d..c0ad8c4ecc 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -4257,7 +4257,45 @@ Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const return reshape(_cn, _newsz[0]); } - CV_Error(CV_StsNotImplemented, ""); + if (isContinuous()) + { + CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz); + + if (_cn == 0) + _cn = this->channels(); + else + CV_Assert(_cn <= CV_CN_MAX); + + size_t total_elem1_ref = this->total() * this->channels(); + size_t total_elem1 = _cn; + + AutoBuffer<int, 4> newsz_buf( (size_t)_newndims ); + + for (int i = 0; i < _newndims; i++) + { + CV_Assert(_newsz[i] >= 0); + + if (_newsz[i] > 0) + newsz_buf[i] = _newsz[i]; + else if (i < dims) + newsz_buf[i] = this->size[i]; + else + CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix"); + + total_elem1 *= (size_t)newsz_buf[i]; + } + + if (total_elem1 != total_elem1_ref) + CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements"); + + Mat hdr = *this; + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT); + setSize(hdr, _newndims, (int*)newsz_buf, NULL, true); + + return hdr; + } + + CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet"); // TBD return Mat(); } diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index 48aa86635d..f378e36113 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -574,12 +574,49 @@ UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const return reshape(_cn, _newsz[0]); } - CV_Error(CV_StsNotImplemented, ""); + if (isContinuous()) + { + CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz); + + if (_cn == 0) + _cn = this->channels(); + else + CV_Assert(_cn <= CV_CN_MAX); + + size_t total_elem1_ref = this->total() * this->channels(); + size_t total_elem1 = _cn; + + AutoBuffer<int, 4> newsz_buf( (size_t)_newndims ); + + for (int i = 0; i < _newndims; i++) + { + CV_Assert(_newsz[i] >= 0); + + if (_newsz[i] > 0) + newsz_buf[i] = _newsz[i]; + else if (i < dims) + newsz_buf[i] = this->size[i]; + else + CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix"); + + total_elem1 *= (size_t)newsz_buf[i]; + } + + if (total_elem1 != total_elem1_ref) + CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements"); + + UMat hdr = *this; + hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT); + setSize(hdr, _newndims, (int*)newsz_buf, NULL, true); + + return hdr; + } + + CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet"); // TBD return UMat(); } - Mat UMat::getMat(int accessFlags) const { if(!u) diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index e2d4e8a4bf..2344df28a5 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1194,6 +1194,73 @@ TEST(Core_Mat, reshape_1942) ASSERT_EQ(1, cn); } +static void check_ndim_shape(const cv::Mat &mat, int cn, int ndims, const int *sizes) +{ + EXPECT_EQ(mat.channels(), cn); + EXPECT_EQ(mat.dims, ndims); + + if (mat.dims != ndims) + return; + + for (int i = 0; i < ndims; i++) + EXPECT_EQ(mat.size[i], sizes[i]); +} + +TEST(Core_Mat, reshape_ndims_2) +{ + const cv::Mat A(8, 16, CV_8UC3); + cv::Mat B; + + { + int new_sizes_mask[] = { 0, 3, 4, 4 }; + int new_sizes_real[] = { 8, 3, 4, 4 }; + ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask)); + check_ndim_shape(B, 1, 4, new_sizes_real); + } + { + int new_sizes[] = { 16, 8 }; + ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes)); + check_ndim_shape(B, 3, 2, new_sizes); + EXPECT_EQ(B.rows, new_sizes[0]); + EXPECT_EQ(B.cols, new_sizes[1]); + } + { + int new_sizes[] = { 2, 5, 1, 3 }; + cv::Mat A_sliced = A(cv::Range::all(), cv::Range(0, 15)); + ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes)); + } +} + +TEST(Core_Mat, reshape_ndims_4) +{ + const int sizes[] = { 2, 6, 4, 12 }; + const cv::Mat A(4, sizes, CV_8UC3); + cv::Mat B; + + { + int new_sizes_mask[] = { 0, 864 }; + int new_sizes_real[] = { 2, 864 }; + ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask)); + check_ndim_shape(B, 1, 2, new_sizes_real); + EXPECT_EQ(B.rows, new_sizes_real[0]); + EXPECT_EQ(B.cols, new_sizes_real[1]); + } + { + int new_sizes_mask[] = { 4, 0, 0, 2, 3 }; + int new_sizes_real[] = { 4, 6, 4, 2, 3 }; + ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask)); + check_ndim_shape(B, 3, 5, new_sizes_real); + } + { + int new_sizes_mask[] = { 1, 1 }; + ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask)); + } + { + int new_sizes_mask[] = { 4, 6, 3, 3, 0 }; + ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask)); + } +} + TEST(Core_Mat, push_back) { Mat a = (Mat_<float>(1,2) << 3.4884074f, 1.4159607f); diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp index 0e25b6ba9a..c4cdf14ee6 100644 --- a/modules/core/test/test_umat.cpp +++ b/modules/core/test/test_umat.cpp @@ -350,6 +350,73 @@ TEST_P(UMatTestReshape, DISABLED_reshape) INSTANTIATE_TEST_CASE_P(UMat, UMatTestReshape, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, UMAT_TEST_SIZES, Bool() )); +static void check_ndim_shape(const cv::UMat &mat, int cn, int ndims, const int *sizes) +{ + EXPECT_EQ(mat.channels(), cn); + EXPECT_EQ(mat.dims, ndims); + + if (mat.dims != ndims) + return; + + for (int i = 0; i < ndims; i++) + EXPECT_EQ(mat.size[i], sizes[i]); +} + +TEST(UMatTestReshape, reshape_ndims_2) +{ + const cv::UMat A(8, 16, CV_8UC3); + cv::UMat B; + + { + int new_sizes_mask[] = { 0, 3, 4, 4 }; + int new_sizes_real[] = { 8, 3, 4, 4 }; + ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask)); + check_ndim_shape(B, 1, 4, new_sizes_real); + } + { + int new_sizes[] = { 16, 8 }; + ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes)); + check_ndim_shape(B, 3, 2, new_sizes); + EXPECT_EQ(B.rows, new_sizes[0]); + EXPECT_EQ(B.cols, new_sizes[1]); + } + { + int new_sizes[] = { 2, 5, 1, 3 }; + cv::UMat A_sliced = A(cv::Range::all(), cv::Range(0, 15)); + ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes)); + } +} + +TEST(UMatTestReshape, reshape_ndims_4) +{ + const int sizes[] = { 2, 6, 4, 12 }; + const cv::UMat A(4, sizes, CV_8UC3); + cv::UMat B; + + { + int new_sizes_mask[] = { 0, 864 }; + int new_sizes_real[] = { 2, 864 }; + ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask)); + check_ndim_shape(B, 1, 2, new_sizes_real); + EXPECT_EQ(B.rows, new_sizes_real[0]); + EXPECT_EQ(B.cols, new_sizes_real[1]); + } + { + int new_sizes_mask[] = { 4, 0, 0, 2, 3 }; + int new_sizes_real[] = { 4, 6, 4, 2, 3 }; + ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask)); + check_ndim_shape(B, 3, 5, new_sizes_real); + } + { + int new_sizes_mask[] = { 1, 1 }; + ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask)); + } + { + int new_sizes_mask[] = { 4, 6, 3, 3, 0 }; + ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask)); + } +} + ////////////////////////////////////////////////////////////////// ROI testing /////////////////////////////////////////////////////////////// PARAM_TEST_CASE(UMatTestRoi, int, int, Size)