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?
In OpenCV the main matrix class is called Mat and is contained in the OpenCV-namespace cv. This matrix is not templated but nevertheless can contain different data types. These are indicated by a certain type-number. Additionally, OpenCV provides a templated class called Mat_, which is derived from Mat.
CV_64F is the same as CV_64FC1 . So if you need just 2D matrix (i.e. single channeled) you can just use CV_64F. EDIT. More generally, type name of a Mat object consists of several parts.
Vec3b is the abbreviation for "vector with 3 byte entries" Here those byte entries are unsigned char values to represent values between 0 .. 255.
Scalar Represents a 4-element vector. The type Scalar is widely used in OpenCV for passing pixel values. In this tutorial, we will use it extensively to represent BGR color values (3 parameters). It is not necessary to define the last argument if it is not going to be used.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With