Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 354
Sreemanananth Sadanand Avatar asked Jun 13 '12 14:06

Sreemanananth Sadanand


People also ask

What is a CV :: mat?

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.

What is CV_64F?

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.

What is Vec3b OpenCV?

Vec3b is the abbreviation for "vector with 3 byte entries" Here those byte entries are unsigned char values to represent values between 0 .. 255.

What is scalar OpenCV?

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.


1 Answers

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.

like image 60
karlphillip Avatar answered Sep 27 '22 23:09

karlphillip