1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #27757 from vpisarev:matshape_inside_mat

Use MatShape instead of MatSize inside cv::Mat/cv::UMat #27757

**Merge together with https://github.com/opencv/opencv_contrib/pull/3996**
---

This PR continues cv::Mat/cv::UMat refactoring. See #26056, where `MatShape` was introduced. Now it's put inside cv::Mat/cv::UMat instead of a weird `MatSize`. MatSize is now an alias for MatShape:

**before:**

```
struct MatShape { ... };
struct MatSize { ... };

struct Mat {
    ...
    int dims;
    int rows;
    int cols;

    ...

    MatShape shape() const { ... /* constructs MatShape out of MatSize and returns it;
                                    layout is always 'unknown', because we don't store it */ }

    MatSize size; // size is not valid without the parent cv::Mat,
                  // because size.p may point to Mat::rows or to Mat::cols,
                  // depending on the dimensionality, and dims() returns Mat::dims.
    MatStep step; // may allocate memory, depending on the dimensionality.
    ...
};
```

**after:**

```
struct MatShape { ... };
typedef MatShape MatSize; // they are now synonyms

struct Mat {
    ...
    int dims;
    int rows;
    int cols;

    ...

    MatShape shape() const { return size; } // just return the embedded shape (including the proper layout information)

    MatSize size; // size is self-contained data structure that can be used without the parent cv::Mat.
                  // size.dims is now a copy of dims; size.p[*] contains copies of Mat::rows and Mat::cols when dims <= 2.
    MatStep step; // does not allocate extra memory buffers.
    ...
};
```

There are several reasons to do that:

1. the main reason is to be able to store data layout (MatShape::layout) inside each cv::Mat/cv::UMat. This is necessary for the proper shape inference in DNN module. In particular, it's necessary for the next step of DNN inference optimization where we introduce block-layout-optimized convolution and other operations. Later on, we can use layout information to support non-interleaved images (e.g. RRR...GGG...BBB...) or even batches of such images in core/imgproc modules.
2. the other reason is to represent 3D/4D/5D etc. tensors as cv::Mat/cv::UMat instances more conveniently, without extra dynamic memory allocation. Before this patch we allocated some memory buffers dynamically to store shape & steps for more than 2D arrays. Now the whole cv::Mat/cv::UMat header can be stored completely on stack/in a container. Creating another copy of Mat/UMat header is now done more efficiently.
3. the third reason is to introduce the new coding pattern: `dst.create(src.size, <dst_type>);`. The pattern is suitable for most of element-wise (including cloning) and filtering operations. This pattern does not only look crisp and self-documenting, it will also automatically copy shape (including layout) from the source tensor into the destination matrix/tensor.
4. in the future we might add `colorspace` member to MatShape that will allow to distinguish RGB from BGR or NV12. `dst.create(src.size, <dst_type>);` will then copy the colorspace information as well.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Vadim Pisarevsky
2025-09-15 15:03:34 +03:00
committed by GitHub
parent abcfb3c1e7
commit bdab54f79e
52 changed files with 521 additions and 624 deletions
+17 -17
View File
@@ -100,7 +100,7 @@ TEST_P(Test_NaryEltwise_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
@@ -175,7 +175,7 @@ TEST_P(Test_Const_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
@@ -281,7 +281,7 @@ TEST_P(Test_ScatterND_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
ASSERT_EQ(shape(input), shape(re));
std::vector<int> reIndices(4);
@@ -364,7 +364,7 @@ TEST_P(Test_Concat_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1] + input2.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
@@ -441,7 +441,7 @@ TEST_P(Test_ArgMax_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), CV_64S);
EXPECT_EQ(re.size.dims(), 3);
EXPECT_EQ(re.size.dims, 3);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);
EXPECT_EQ(re.size[2], inShape[3]);
@@ -510,7 +510,7 @@ TEST_P(Test_Blank_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 4);
@@ -568,7 +568,7 @@ TEST_P(Test_Expand_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 4);
@@ -631,7 +631,7 @@ TEST_P(Test_Permute_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 4);
EXPECT_EQ(re.size[2], 5);
@@ -705,7 +705,7 @@ TEST_P(Test_GatherElements_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
ASSERT_EQ(shape(indicesMat), shape(re));
std::vector<int> inIndices(4);
@@ -823,7 +823,7 @@ TEST_P(Test_Cast_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), outMatType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
ASSERT_EQ(shape(input), shape(re));
normAssert(outputRef, re);
@@ -865,7 +865,7 @@ TEST_P(Test_Pad_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 5);
@@ -940,7 +940,7 @@ TEST_P(Test_Slice_Int, random)
Mat out = net.forward();
Mat gt = input(range);
EXPECT_EQ(out.size.dims(), 4);
EXPECT_EQ(out.size.dims, 4);
EXPECT_EQ(out.size[0], gt.size[0]);
EXPECT_EQ(out.size[1], gt.size[1]);
EXPECT_EQ(out.size[2], gt.size[2]);
@@ -981,7 +981,7 @@ TEST_P(Test_Reshape_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], outShape[0]);
EXPECT_EQ(re.size[1], outShape[1]);
EXPECT_EQ(re.size[2], outShape[2]);
@@ -1022,7 +1022,7 @@ TEST_P(Test_Flatten_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 2);
EXPECT_EQ(re.size.dims, 2);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[1] * inShape[2] * inShape[3]);
@@ -1062,7 +1062,7 @@ TEST_P(Test_Tile_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size.dims, 4);
EXPECT_EQ(re.size[0], inShape[0] * repeats[0]);
EXPECT_EQ(re.size[1], inShape[1] * repeats[1]);
EXPECT_EQ(re.size[2], inShape[2] * repeats[2]);
@@ -1142,7 +1142,7 @@ TEST_P(Test_Reduce_Int, random)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 3);
EXPECT_EQ(re.size.dims, 3);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);
EXPECT_EQ(re.size[2], inShape[3]);
@@ -1219,7 +1219,7 @@ TEST_P(Test_Reduce_Int, two_axes)
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 2);
EXPECT_EQ(re.size.dims, 2);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);