Sreemanananth Sadanand
Sreemanananth Sadanand

Reputation: 233

Simple passing of Matrices ie. cv::Mat to functions in OpenCV2.4

I am new to opencv and I have a doubt with one of the simplest operations in coding: Passing values to functions.

Heres what I want to do,

  1. Initialize a cv:Mat in the main function with say, values from 0 to 50.
  2. Pass this matrix as an argument to a function foo() which in turn simply prints out the values of each element in the matrix. Thats it.

Now I have read in multiple places that when these matrices are passed, it is only the header that gets passed, not the actual data. Then how am I still able to read out the values of this matrix in the called function as if the entire matrix was passed?

Upvotes: 15

Views: 11431

Answers (1)

karlphillip
karlphillip

Reputation: 93410

To understand what's going on you need to take a look at C++ constructors, more specifically the copy constructor.

When you create a cv::Mat from another cv::Mat, as in:

cv::Mat a = cv::imread("huge.png", 1);
cv::Mat b = a;

the copy constructor (which is a function) of cv::Mat is called to perform the copy of the object. Before I talk about what happens in the copy procedure, you must realize that as cv::Mat is used to store images, larger images might occupy hundreds of megabytes in memory. So what the copy constructor of cv::Mat does in the example above is copy the entire header (height, width, depth info and others) of a into b, but instead of copying the entire data/pixels of a (which might be hundreds of MB), it just points (using a pointer) to the original data of a.

In other words, not copying the entire image data is an optimization/performance decision.

Now, consider this code that calls a function and passes cv::Mat as a parameter:

void do_something(cv::Mat src)
{
    // changing src pixels will be the same as changing orig pixels
}

int main()
{
    cv::Mat orig = cv::imread("huge.png", 1);
    do_something(orig);
    return 0;
}

If you have studied how to pass parameters to functions, you know that calling do_something(a); will pass the parameter by value. This means that it will try to copy the content of orig into src, however, this procedure activates the copy constructor of cv::Mat which will not make a hard copy of the data as I've just explained.

Solution to this problem? If you are writing do_something() and you just want to make a real copy of orig, just create a new cv::Mat and call the method copyTo():

void do_something(cv::Mat src)
{
    cv::Mat real_copy = src.copyTo();
    // operating on the data of real_copy will not affect orig
}

But remember, if src is ~100MB calling copyTo() to make the real copy will occupy another ~100MB of memory, which means that in a single function call your program just went from 100MB to 200MB. Keep this in mind when designing your system. Good luck.

Upvotes: 35

Related Questions