Reputation: 233
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,
cv:Mat
in the main function with say, values from 0 to 50.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
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