0

I am using OpenCV 4.1.1. and have the following goal

Given a Mat of size (m, n, 2) of float32, create separate Mat headers for each individual channel, so that it can be written to, without copying the image data

What I am trying to do is this:

  const int mat_sz[]{shape_.height, shape_.width, 2};
  Mat cost(3, mat_sz, CV_32F);

  Mat channel1(
      shape_, CV_32FC1,  /* 1 channel Mat has FC1 type*/
      cost.ptr<float>(), /* data ptr */
      cost.step[2] * 2 /* orig stride/step should be 4 for float, x2 because
                          we want every  other */
  );
  channel1(Rect(0, 0, 100, 100)) = 255;

  Mat channel2(
      shape_, CV_32FC1, cost.ptr<float>() + 1, // +1 so we start at the  second channel  element
      cost.step[2] * 2);
  channel2(Rect(0, 0, 100, 100)) = 128;

I can see by normalizeing and imshowing the two channels that

  • rectangle selection seems not to work in this case, instead pixels get filled from the top, maybe operator(Rect) doesnt do what I want in this case.
  • the values which should go into channel 2 show up in channel 1 and vise versa

What am I doing wrong?


I'm using this code to display the matrix:

#define DISPLAY(m)                                                             \
  {                                                                            \
    Mat _tmp##m;                                                               \
    normalize(m, _tmp##m, 0, 1, NORM_MINMAX);                                  \
    imshow(#m, _tmp##m);                                                       \
    waitKey(0);                                                                \
  }
oarfish
  • 4,116
  • 4
  • 37
  • 66
  • 1
    that's not possible, because of the memory layout and direct access. If opencv wasn't optimized for speed ot could implement it by defining a channel step value (the distance between two pixels in memory). But now you can only use the split and merge functions, which are using clones. – Micka Sep 05 '20 at 06:33
  • But then what good is the step parameter for a matrix if it's not used? Or is the calculation wrong? Channel values for each pixel are laid out one after the other, so according to the documentation, this should work I think. – oarfish Sep 05 '20 at 08:13
  • Or are you saying its only the row step that's really used, and the assumption is that cols and channels are always contiguous? – oarfish Sep 05 '20 at 08:15
  • If the above doesnt work, I'm wondering how `NAryMatIterator` works, unless it does somehow copy, in which case this answer here would not work: https://stackoverflow.com/a/8809877/2397253 – oarfish Sep 05 '20 at 08:24
  • On further consideration, the doc does say for the step parameter for multidimensional `Mat`s: `Array of ndims-1 steps in case of a multi-dimensional array (the last step is always set to the element size)`. So there seems to be the assumption of the last (channel) dimension to be contiguous. – oarfish Sep 05 '20 at 08:34
  • I only know about the row-step, which is used for efficient sub-imaging and padded data for SSE instructions. If there is an element-step, maybe you can use it with elrment-iterators – Micka Sep 05 '20 at 10:07

1 Answers1

0

Turns out this is not possible, because the documentation for the cv::Mat constructor taking in number dimension, their sizes and preallocated data states that

steps: Array of ndims-1 steps in case of a multi-dimensional array (the last step is always set to the element size). If not specified, the matrix is assumed to be continuous.

So the last dimension cannot be strided and is always assumed to be contiguous in memory. A value passed for this dimension is ignored.

oarfish
  • 4,116
  • 4
  • 37
  • 66