1

I am quite comfortable with OpenCV in Python. I recently switched to the C++ version, and I keep having problems with the cv::Mat indexing, since I'm too used to numpy's arrays. In particular, I am trying to find if there is a better way of acting on a restricted area of an array without iterating through it. For example, let's say I have a 10x15 unitary matrix and I would like to put everything but the last row to zero (or to another random number); in Python, I would do something like this:

import numpy as np

a = np.ones([10,15])
a[:-1,:-1] = 0

How can I achieve that in C++, having defined cv::Mat a = cv::Mat::ones(10, 15, CV_32FC1);?

Eggman
  • 53
  • 2
  • 14

2 Answers2

1

The best way is probably to use regions of interest. A cv mat can easily be partitioned by using a rect in the following way:

using namespace cv;

Mat a = Mat::ones(10, 15, CV_32FC1);
Rect rect(2, 2, 4, 4);
Mat roi = a(rect);

you can hereafter modify the roi in whatever fashion you like, put back in a by:

 roi.copyTo(a(rect));

You can elegantly use a new Rect in the previous line, as long as its width and height are the same as the original Rect. To solve your specific question, the easiest way is to make a new matrix with all zeros, and then use copyTo with that one.

Stefan Karlsson
  • 1,092
  • 9
  • 21
  • That's what I needed, thank you! I just add that, looking into it, a couple of `cv::Range` vectors can be used (e.g. `m(cv::Range(i0,i1), cv::Range(j0,j1))` does a trick equivalent to `m(cv::Rect(i0,i1,j0-i0,j1-i1))`. – Eggman Jul 19 '18 at 12:59
  • 1
    great to help. Bear in mind that while the original numpy code you posted is the fastest way to do this for numpy, do not expect this to be the fastest way to do it in c++. In either case, it should be much faster then numpy – Stefan Karlsson Jul 20 '18 at 09:56
0

I don't know if this is the most efficient way of doing this and if it's not then someone will correct me.

One way would be to set the image to value row by row

for (int i = 0; i < image.rows-1; ++i)
{
  image.row(i).setTo(Scalar(0,0,0));
}

Or if the image data pointer is continues then use std::fill

if(image.isContinuous())
    std::fill_n(image.data, (image.rows-1) * image.cols * image.elemSize(), 0);
zindarod
  • 6,328
  • 3
  • 30
  • 58