Eslam Ahmed
Eslam Ahmed

Reputation: 302

Mat& vs Mat opencv 2 c++

well I’m a little confused about passing Mat to function and retrieving it so what is the difference between let's say

 void GetFrame(Mat& frame)
          Vs 
 void GetFrame(Mat frame) 
          Vs 
 Mat GetFrame()

Update:

in which version the changes to frame inside the function body will result in change in the original frame passed to function

Upvotes: 2

Views: 2425

Answers (2)

Sam
Sam

Reputation: 1

"2. Pass by value version" is INCORRECT, at least for the below example which drove me nuts, but I managed to fix using .clone()

Mat image = imread("anyimage.jpg");
Rect rect(Point(40, 50), Point(60,80) ); // assuming size is over 80
if(!image.empty())
{
imshow("original image",image);
waitKey(0);

test_if_it_adds_a_rect(image, rect);
imshow("returned image",image);
waitKey(0);
}

//and here is the function

void test_if_it_adds_a_rect(Mat image, Rect rect)
{
 rectangle(image, rect, CV_RGB(0, 0, 255), 2); 
}

//even this one

void test_if_it_adds_a_rect(Mat image1, Rect rect1)
{
rectangle(image1, rect1, CV_RGB(0, 0, 255), 2); 
}

You will notice that the returned image has changed and has a blue rect. BUT to solve this you need to use image.clone() inside the function instead of image

Upvotes: 0

Nicu Stiurca
Nicu Stiurca

Reputation: 8697

With a bit of care, you can get all 3 versions to work and do the same thing, but I will try to explain the details.

First, a Mat object is really just a small header which contains metadata about the real data, (eg, number of rows and columns), and a pointer to the actual data. In most cases, the pointer is actually a smart pointer, with reference counting, and can be shared by multiple Mat objects, and automatically deleted when the last remaining Mat object stops pointing to it. (Mat objects can also point to data it doesn't own, ie if you have some data you got from a different library/API, and want to reuse the same memory rather than copy it.)

1. Pass by reference version

Version 1 of your function is perhaps the simplest. The caller's Mat object is copied by reference, which obviously means that any modifications to the Mat object's metadata (including the (smart) pointer) will be visible to the caller upon return. The underlying data will obviously reflect any modification made by the function.

2. Pass by value version

In version 2 of your function (passing in a Mat object by value), the small header represented by Mat is copied and passed to the function. The copy is shallow: metadata and the (smart) pointer is copied, but the underlying data is shared by the caller's Mat object and the callee's Mat object. The part that you have to be careful is that if the function modifies the metadata of the copied frame object, these changes will not be visible to the caller.

So for example, if you pass an empty Mat, you may be surprised with the result: First, the meta-data of the empty Mat is copied. When the function calls something like frame.create(newRows, newCols, newType);, the create function will allocate a new chunk of memory since frame.rows != newRows, frame.cols != newCols, and frame.type() != newType, and the (callee's copy alone of) frame metadata is updated reflect the newly allocated data. When the function returns, its frame object will hold the only reference to the smart pointer, so the data will be automatically discarded. The caller will still have just an empty header.

If, however, the Mat object that is passed in to the function already has the correct dimensions and type, frame.create() will do nothing, which means that any modification made by the callee to the underlying data will be visible to the caller.

3. Return by value version

The 3rd version is similar to the second, except that rather than making a copy of the meta-data when the function is called, the function instead allocates a Mat however it sees fit, and the meta-data (including pointer to the underlying data) is copied back to the caller upon return. The underlying data survives and is accessible to the caller.

Summary

If you don't know the size and type of the data ahead of time, you cannot use pass-by-value. If you do know the size/type, you can use pass-by-value, and the pre-allocated memory will be used.

Pass-by-reference will use the pre-allocated memory if possible, or allocate new memory, and in either case the caller will always see the new header/data.

Return-by-value also will always work properly, but it does have to re-allocate new memory every call, which may be undesirable.

Upvotes: 5

Related Questions