Reputation: 302
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
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
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.)
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.
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.
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.
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