Skip to content

Commit 85cc11e

Browse files
author
Vitaliy Lyudvichenko
committed
Changed behaviour of Mat/UMat::reshape() to accept n-dim shapes
1 parent 0726c4d commit 85cc11e

File tree

4 files changed

+212
-3
lines changed

4 files changed

+212
-3
lines changed

modules/core/src/matrix.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4257,7 +4257,45 @@ Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const
42574257
return reshape(_cn, _newsz[0]);
42584258
}
42594259

4260-
CV_Error(CV_StsNotImplemented, "");
4260+
if (isContinuous())
4261+
{
4262+
CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
4263+
4264+
if (_cn == 0)
4265+
_cn = this->channels();
4266+
else
4267+
CV_Assert(_cn <= CV_CN_MAX);
4268+
4269+
size_t total_elem1_ref = this->total() * this->channels();
4270+
size_t total_elem1 = _cn;
4271+
4272+
AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
4273+
4274+
for (int i = 0; i < _newndims; i++)
4275+
{
4276+
CV_Assert(_newsz[i] >= 0);
4277+
4278+
if (_newsz[i] > 0)
4279+
newsz_buf[i] = _newsz[i];
4280+
else if (i < dims)
4281+
newsz_buf[i] = this->size[i];
4282+
else
4283+
CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
4284+
4285+
total_elem1 *= (size_t)newsz_buf[i];
4286+
}
4287+
4288+
if (total_elem1 != total_elem1_ref)
4289+
CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements");
4290+
4291+
Mat hdr = *this;
4292+
hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
4293+
setSize(hdr, _newndims, (int*)newsz_buf, NULL, true);
4294+
4295+
return hdr;
4296+
}
4297+
4298+
CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
42614299
// TBD
42624300
return Mat();
42634301
}

modules/core/src/umatrix.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,49 @@ UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
574574
return reshape(_cn, _newsz[0]);
575575
}
576576

577-
CV_Error(CV_StsNotImplemented, "");
577+
if (isContinuous())
578+
{
579+
CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
580+
581+
if (_cn == 0)
582+
_cn = this->channels();
583+
else
584+
CV_Assert(_cn <= CV_CN_MAX);
585+
586+
size_t total_elem1_ref = this->total() * this->channels();
587+
size_t total_elem1 = _cn;
588+
589+
AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
590+
591+
for (int i = 0; i < _newndims; i++)
592+
{
593+
CV_Assert(_newsz[i] >= 0);
594+
595+
if (_newsz[i] > 0)
596+
newsz_buf[i] = _newsz[i];
597+
else if (i < dims)
598+
newsz_buf[i] = this->size[i];
599+
else
600+
CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
601+
602+
total_elem1 *= (size_t)newsz_buf[i];
603+
}
604+
605+
if (total_elem1 != total_elem1_ref)
606+
CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements");
607+
608+
UMat hdr = *this;
609+
hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
610+
setSize(hdr, _newndims, (int*)newsz_buf, NULL, true);
611+
612+
return hdr;
613+
}
614+
615+
CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
578616
// TBD
579617
return UMat();
580618
}
581619

582-
583620
Mat UMat::getMat(int accessFlags) const
584621
{
585622
if(!u)

modules/core/test/test_mat.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,73 @@ TEST(Core_Mat, reshape_1942)
11941194
ASSERT_EQ(1, cn);
11951195
}
11961196

1197+
static void check_ndim_shape(const cv::Mat &mat, int cn, int ndims, const int *sizes)
1198+
{
1199+
EXPECT_EQ(mat.channels(), cn);
1200+
EXPECT_EQ(mat.dims, ndims);
1201+
1202+
if (mat.dims != ndims)
1203+
return;
1204+
1205+
for (int i = 0; i < ndims; i++)
1206+
EXPECT_EQ(mat.size[i], sizes[i]);
1207+
}
1208+
1209+
TEST(Core_Mat, reshape_ndims_2)
1210+
{
1211+
const cv::Mat A(8, 16, CV_8UC3);
1212+
cv::Mat B;
1213+
1214+
{
1215+
int new_sizes_mask[] = { 0, 3, 4, 4 };
1216+
int new_sizes_real[] = { 8, 3, 4, 4 };
1217+
ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask));
1218+
check_ndim_shape(B, 1, 4, new_sizes_real);
1219+
}
1220+
{
1221+
int new_sizes[] = { 16, 8 };
1222+
ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes));
1223+
check_ndim_shape(B, 3, 2, new_sizes);
1224+
EXPECT_EQ(B.rows, new_sizes[0]);
1225+
EXPECT_EQ(B.cols, new_sizes[1]);
1226+
}
1227+
{
1228+
int new_sizes[] = { 2, 5, 1, 3 };
1229+
cv::Mat A_sliced = A(cv::Range::all(), cv::Range(0, 15));
1230+
ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes));
1231+
}
1232+
}
1233+
1234+
TEST(Core_Mat, reshape_ndims_4)
1235+
{
1236+
const int sizes[] = { 2, 6, 4, 12 };
1237+
const cv::Mat A(4, sizes, CV_8UC3);
1238+
cv::Mat B;
1239+
1240+
{
1241+
int new_sizes_mask[] = { 0, 864 };
1242+
int new_sizes_real[] = { 2, 864 };
1243+
ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask));
1244+
check_ndim_shape(B, 1, 2, new_sizes_real);
1245+
EXPECT_EQ(B.rows, new_sizes_real[0]);
1246+
EXPECT_EQ(B.cols, new_sizes_real[1]);
1247+
}
1248+
{
1249+
int new_sizes_mask[] = { 4, 0, 0, 2, 3 };
1250+
int new_sizes_real[] = { 4, 6, 4, 2, 3 };
1251+
ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask));
1252+
check_ndim_shape(B, 3, 5, new_sizes_real);
1253+
}
1254+
{
1255+
int new_sizes_mask[] = { 1, 1 };
1256+
ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask));
1257+
}
1258+
{
1259+
int new_sizes_mask[] = { 4, 6, 3, 3, 0 };
1260+
ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask));
1261+
}
1262+
}
1263+
11971264
TEST(Core_Mat, push_back)
11981265
{
11991266
Mat a = (Mat_<float>(1,2) << 3.4884074f, 1.4159607f);

modules/core/test/test_umat.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,73 @@ TEST_P(UMatTestReshape, DISABLED_reshape)
350350

351351
INSTANTIATE_TEST_CASE_P(UMat, UMatTestReshape, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, UMAT_TEST_SIZES, Bool() ));
352352

353+
static void check_ndim_shape(const cv::UMat &mat, int cn, int ndims, const int *sizes)
354+
{
355+
EXPECT_EQ(mat.channels(), cn);
356+
EXPECT_EQ(mat.dims, ndims);
357+
358+
if (mat.dims != ndims)
359+
return;
360+
361+
for (int i = 0; i < ndims; i++)
362+
EXPECT_EQ(mat.size[i], sizes[i]);
363+
}
364+
365+
TEST(UMatTestReshape, reshape_ndims_2)
366+
{
367+
const cv::UMat A(8, 16, CV_8UC3);
368+
cv::UMat B;
369+
370+
{
371+
int new_sizes_mask[] = { 0, 3, 4, 4 };
372+
int new_sizes_real[] = { 8, 3, 4, 4 };
373+
ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask));
374+
check_ndim_shape(B, 1, 4, new_sizes_real);
375+
}
376+
{
377+
int new_sizes[] = { 16, 8 };
378+
ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes));
379+
check_ndim_shape(B, 3, 2, new_sizes);
380+
EXPECT_EQ(B.rows, new_sizes[0]);
381+
EXPECT_EQ(B.cols, new_sizes[1]);
382+
}
383+
{
384+
int new_sizes[] = { 2, 5, 1, 3 };
385+
cv::UMat A_sliced = A(cv::Range::all(), cv::Range(0, 15));
386+
ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes));
387+
}
388+
}
389+
390+
TEST(UMatTestReshape, reshape_ndims_4)
391+
{
392+
const int sizes[] = { 2, 6, 4, 12 };
393+
const cv::UMat A(4, sizes, CV_8UC3);
394+
cv::UMat B;
395+
396+
{
397+
int new_sizes_mask[] = { 0, 864 };
398+
int new_sizes_real[] = { 2, 864 };
399+
ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask));
400+
check_ndim_shape(B, 1, 2, new_sizes_real);
401+
EXPECT_EQ(B.rows, new_sizes_real[0]);
402+
EXPECT_EQ(B.cols, new_sizes_real[1]);
403+
}
404+
{
405+
int new_sizes_mask[] = { 4, 0, 0, 2, 3 };
406+
int new_sizes_real[] = { 4, 6, 4, 2, 3 };
407+
ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask));
408+
check_ndim_shape(B, 3, 5, new_sizes_real);
409+
}
410+
{
411+
int new_sizes_mask[] = { 1, 1 };
412+
ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask));
413+
}
414+
{
415+
int new_sizes_mask[] = { 4, 6, 3, 3, 0 };
416+
ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask));
417+
}
418+
}
419+
353420
////////////////////////////////////////////////////////////////// ROI testing ///////////////////////////////////////////////////////////////
354421

355422
PARAM_TEST_CASE(UMatTestRoi, int, int, Size)

0 commit comments

Comments
 (0)