我对将Mat传递给函数并检索它有点困惑 那么让我们说
之间的区别是什么 void GetFrame(Mat& frame)
Vs
void GetFrame(Mat frame)
Vs
Mat GetFrame()
更新
在哪个版本中,对函数体内部框架的更改将导致传递给函数
的原始框架发生更改答案 0 :(得分:4)
有点小心,你可以让所有3个版本都能正常工作并做同样的事情,但我会尝试解释细节。
首先,Mat
对象实际上只是一个小标题,其中包含有关实际数据的元数据(例如,行数和列数),以及指向实际数据的指针。在大多数情况下,指针实际上是一个带引用计数的智能指针,可以由多个Mat
对象共享,并在最后剩余的Mat
对象停止指向它时自动删除。 (Mat
个对象也可以指向它不拥有的数据,即如果你有一些来自不同库/ API的数据,并希望重用相同的内存而不是复制它。)< / em>的
你的功能的第1版可能是最简单的。调用者的Mat
对象通过引用复制,这显然意味着调用者可以看到对Mat
对象的元数据(包括(智能)指针)的任何修改。返回。基础数据显然会反映该功能所做的任何修改。
在函数的第2版中(按值传递Mat
个对象),Mat
表示的小标题被复制并传递给函数。副本很浅:元数据和(智能)指针被复制,但底层数据由调用者的Mat
对象和被调用者的Mat
对象共享。您必须小心的部分是,如果函数修改了复制的frame
对象的元数据,调用者将无法看到这些更改。
例如,如果您传递空Mat
,您可能会对结果感到惊讶:首先,复制空Mat
的元数据。当函数调用frame.create(newRows, newCols, newType);
之类的函数时,create
函数将分配一个新的内存块,因为frame.rows != newRows
,frame.cols != newCols
和frame.type() != newType
以及(被调用者)单独复制frame
元数据更新反映新分配的数据。当函数返回时,其frame
对象将保留对智能指针的唯一引用,因此数据将被自动丢弃。调用者仍然只有一个空标题。
但是,如果传递给函数的Mat
对象已经具有正确的维度和类型,则frame.create()
将不执行任何操作,这意味着被调用者对基础进行的任何修改数据将对调用者可见。
第三个版本与第二个版本类似,不同之处在于,当调用函数时,函数不是复制元数据,而是分配Mat
,但它认为合适,并且元数据(包括指向底层数据的指针)在返回时被复制回调用者。基础数据存活并且可以被调用者访问。
如果您未提前知道数据的大小和类型,则无法使用传值。如果您确实知道大小/类型,则可以使用pass-by-value,并使用预分配的内存。
传递引用将尽可能使用预先分配的内存,或者分配新的内存,在任何一种情况下,调用者都将始终看到新的头/数据。
按值返回也将始终正常工作,但它必须在每次调用时重新分配新内存,这可能是不合需要的。
答案 1 :(得分:0)
&#34; 2。通过价值版本&#34;是不正确的,至少在下面的例子中让我疯了,但我设法修复使用.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);
}
//这里是函数
void test_if_it_adds_a_rect(Mat image, Rect rect)
{
rectangle(image, rect, CV_RGB(0, 0, 255), 2);
}
//甚至这一个
void test_if_it_adds_a_rect(Mat image1, Rect rect1)
{
rectangle(image1, rect1, CV_RGB(0, 0, 255), 2);
}
您会注意到返回的图像已更改并且具有蓝色矩形。 但要解决这个问题,你需要在函数内使用image.clone()而不是image