Slicing operation help

Can someone explain how one would do this sclicing operation in c++ opencv
y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + grid) * stride
when y is with a shape(1,3,80,80,85).
I know that I can extract it with the range using ROI but when I do the computation with the submatrix. How do put the ROI back to original matrix. Any suggestions welcome.

Hello,

As far as I know, operating on a ROI only creates a view of the original Mat, not a new data buffer, so any computation performed on the ROI will effectively be reflected in the original Mat as well.

You might be interested in functions
operator() and locateROI

I eventually did it with using ranges with cv::Mat subarray = input_array(ranges); but the problem is that how do I re-apply the submatrix to the input_array. The internet suggests

cv::mat subarray = input_array(ranges)
cv::mat tmp = input_array.clone()
subarray.copyTo(tmp)

input_array is what ?
(not part of the API)
and why the clone() ?

also, can you please explain the context of your operation ?
(even in python, those 2 lines don’t seem to fit together for me …)

I’ll clarify then. Lets say you have an Mat with dimensions (3,80,80,85) lets call it input_array, you need to extract a sub matrix with (3,80,80,2) which is done with following code.

const int sz[] = {3,80,80,85};
cv::Mat input_array(4,sz,CV_32F,cv::Scalar(114.0));
std::vector<cv::Range> ranges;
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range(0, 2));

cv::Mat subarray = input_array(ranges);
subarray = (subarray * 2 - 0.5 + grid) * stride;

Now how do you apply the submatrix changes back to the input_array, the shape of subarray is the same it does not change or is there a better way to do it.

I hope it made things more clear.

1 Like

Dear sycc,

subarray is effectively a view of input_array.
I haven’t debugged your code, but check out the example below (it’s an image and not a general multi-dimensional array because it makes visualization easier):

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <vector>

int main() {
    cv::Mat input_array(80, 80, CV_8UC3, cv::Scalar(255,0,0)); //3 channels, 80x80, completely blue
   
    cv::imshow("", input_array);
    cv::waitKey(0);

    std::vector<cv::Range> ranges;
    ranges.push_back(cv::Range::all());
    ranges.push_back(cv::Range(0, 20));

    cv::Mat subarray = input_array(ranges); //subarray is a view of the first 20 columns of the image
    subarray = cv::Scalar(0, 255, 0); //change the color to green
    cv::imshow("", input_array);
    cv::waitKey(0);

    subarray = subarray / 2; //halven the intensity of the green
    cv::imshow("", input_array);
    cv::waitKey(0);

    return 0;
}

you don’t have to, it happens ‘in-place’:

const int sz[] = {3,8,8,5}; // slightly smaller for viz.
cv::Mat input_array(4,sz,CV_32F,cv::Scalar(1.0));
std::vector<cv::Range> ranges;
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range::all());
  ranges.push_back(cv::Range(0, 2));

cv::Mat subarray = input_array(ranges);
cout << subarray.size << endl;
subarray = subarray * 2; // some op
cout << Mat(8,8,CV_32F,input_array.ptr(0));

3 x 8 x 8 x 2
[2, 2, 1, 1, 1, 2, 2, 1;
 1, 1, 2, 2, 1, 1, 1, 2;
 2, 1, 1, 1, 2, 2, 1, 1;
 1, 2, 2, 1, 1, 1, 2, 2;
 1, 1, 1, 2, 2, 1, 1, 1;
 2, 2, 1, 1, 1, 2, 2, 1;
 1, 1, 2, 2, 1, 1, 1, 2;
 2, 1, 1, 1, 2, 2, 1, 1]