Slicing 3D array into 2D arrays

I have a 3D array

auto m3 = Mat_<float>({2, 2, 2}, {1, 2, 3, 4, 5, 6, 7, 8});

and I would like to slice it into 2D subarrays:

auto m20 = Mat_<float>({2, 2}, {1, 2, 3, 4});
auto m21 = Mat_<float>({2, 2}, {5, 6, 7, 8});

This snippet extracts required elements, but doesn’t reduce dimensionality:

auto m20 = Mat(m3, {Range(0, 1), Range(0, 2), Range(0, 2)});
auto m21 = Mat(m3, {Range(1, 2), Range(0, 2), Range(0, 2)});

What is a concise way to do it?

You can try to reduce dimensionality using data pointer, like this:

m20 = Mat(Size(2, 2), CV_32F, m20.data);
m21 = Mat(Size(2, 2), CV_32F, m21.data);
1 Like

Yes, it works this way, but it’s pretty ugly:

  auto s20 = Mat_<float>(2, 2, (float*)Mat(m3, {Range(0, 1), Range(0, 2), Range(0, 2)}).data);
  auto s21 = Mat_<float>(2, 2, (float*)Mat(m3, {Range(1, 2), Range(0, 2), Range(0, 2)}).data);

I think, since you want to take single “elements” of the outermost dimension, you should be able to use the Mat::row() method. might work, not sure about its behavior on non-2d Mats.

https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a4b22e1c23af7a7f2eef8fa478cfa7434

OpenCV’s Mat type really is made for 2d data with channels. I’m surprised it’s even capable of holding n-dimensional data. a lot of the getters/setters are lacking for that case.

It doesn’t work:

  auto m3 = Mat_<float>({2, 2, 2}, {1, 2, 3, 4, 5, 6, 7, 8});
  cout << m3.row(0).dims << endl;

prints 3, i.e. no reduction of dimension.

1 Like