简体   繁体   English

Mat&vs Mat OpenCV 2 C ++

[英]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 好吧,我对于将Mat传递给函数并进行检索感到有些困惑,所以说之间有什么区别

 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 在哪个版本中,对函数主体内部框架的更改将导致传递给函数的原始框架发生更改

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. 稍加小心,您就可以使所有3个版本都可以工作并执行相同的操作,但是我将尝试解释其详细信息。

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. 首先, Mat对象实际上只是一个小标题,其中包含有关真实数据的元数据(例如,行和列的数量)以及指向实际数据的指针。 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对象共享,并且在最后一个剩余的Mat对象停止指向它时会自动删除。 ( 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.) Mat对象也可以指向它不拥有的数据,即,如果您有一些数据是从其他库/ API获得的,并且想要重用相同的内存而不是复制它。)

1. Pass by reference version 1.通过参考版本

Version 1 of your function is perhaps the simplest. 函数的版本1可能是最简单的。 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. 调用者的Mat对象是通过引用复制 ,这显然意味着对Mat对象的元数据的任何修改(包括(智能)指针)在返回时对调用者都是可见的。 The underlying data will obviously reflect any modification made by the function. 基础数据显然将反映该功能所做的任何修改。

2. Pass by value version 2.按值传递版本

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. 在函数的版本2中(按值传递Mat对象),将Mat表示的小标头复制并传递给函数。 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. 副本是浅:元数据和(智能)指针被复制,但潜在的数据由呼叫者的共享Mat对象和被叫方的Mat对象。 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 . 您需要注意的部分是,如果函数修改了复制的frame对象的元数据, 则调用者将看不到这些更改

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. 因此,例如,如果传递一个空的Mat ,您可能会对结果感到惊讶:首先,复制该空Mat的元数据。 When the function calls something like frame.create(newRows, newCols, newType); 当函数调用诸如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. ,由于frame.rows != newRowsframe.cols != newColsframe.type() != newType ,并且frame元数据(仅被调用方的副本)已更新,因此create函数将分配新的内存块新分配的数据。 When the function returns, its frame object will hold the only reference to the smart pointer, so the data will be automatically discarded. 当函数返回时,其frame对象将保留对智能指针的唯一引用,因此数据将被自动丢弃。 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. 但是,如果传递给函数的Mat对象已经具有正确的尺寸和类型,则frame.create()将不执行任何操作,这意味着被调用方对基础数据进行的任何修改对调用方都是可见的。

3. Return by value version 3.按值返回版本

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. 第三个版本与第二个版本相似,除了第一个版本不是在调用函数时复制元数据,而是在认为合适的情况下分配Mat以及元数据(包括指向基础数据的指针) )会在返回时复制回调用方。 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. 按值返回也将始终正常工作,但是每次调用都必须重新分配新的内存,这可能是不可取的。

"2. Pass by value version" is INCORRECT, at least for the below example which drove me nuts, but I managed to fix using .clone() “ 2.按值传递版本”是不正确的,至少对于下面的示例,这使我很生气,但是我设法使用.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 但是要解决这个问题,您需要在函数内部使用image.clone()而不是image

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM