Mat& 与 Mat opencv 2 c++
Mat& vs Mat opencv 2 c++
好吧,我对将 Mat 传递给函数并检索它有点困惑
那么让我们说
有什么区别
void GetFrame(Mat& frame)
Vs
void GetFrame(Mat frame)
Vs
Mat GetFrame()
更新:
在哪个版本中,对函数体内框架的更改会导致传递给函数的原始框架发生变化
稍加小心,您可以让所有 3 个版本都工作并做同样的事情,但我会尝试解释细节。
首先,Mat
object 实际上只是一个小的 header,其中包含有关真实数据的元数据(例如,行数和列数),以及指向实际数据。大多数情况下,指针其实是一个智能指针,带引用计数,可以被多个Mat
object共享,最后剩下Mat
[=83=时自动删除] 停止指向它。 (Mat
objects 也可以指向它不拥有的数据,即如果你有一些数据是从不同的 library/API 获得的,并且想重用相同的记忆而不是复制它。)
1。通过参考版本
您的函数的版本 1 可能是最简单的。调用者的 Mat
object 通过引用 复制 ,这显然意味着对 Mat
object 的元数据(包括(智能)指针)将在 return 时对调用者可见。底层数据将明显反映函数所做的任何修改。
2。按值传递版本
在您的函数的版本 2 中(按值传入 Mat
object),Mat
表示的小 header 被复制并传递给函数.复制是浅层的:复制了元数据和(智能)指针,但底层数据由调用者的 Mat
object 和被调用者的 Mat
object 共享。您必须注意的部分是,如果函数修改了复制的 frame
object、 的元数据,这些更改将对调用者不可见 。
因此,例如,如果您传递一个空Mat
,您可能会对结果感到惊讶:首先,复制了空Mat
的meta-data。当函数调用类似 frame.create(newRows, newCols, newType);
的东西时,create
函数将分配一个新的内存块,因为 frame.rows != newRows
、frame.cols != newCols
和 frame.type() != newType
,以及(被调用者的单独复制)frame
元数据已更新,反映了新分配的数据。当函数 returns 时,其 frame
object 将保存对智能指针的唯一引用,因此数据将被自动丢弃。调用者仍然只有一个空的 header.
但是,如果传递给函数的 Mat
object 已经具有正确的维度和类型,frame.create()
将不执行任何操作,这意味着所做的任何修改被调用者对底层数据的访问将对调用者可见。
3。 Return 按值版本
第三个版本与第二个版本类似,不同之处在于函数调用时不是复制 meta-data,而是分配它认为合适的 Mat
,并且meta-data(包括指向底层数据的指针)在 return 时被复制回调用者。基础数据仍然存在并且可供调用者访问。
总结
如果您事先不知道数据的大小和类型,则无法使用pass-by-value。如果你确实知道 size/type,你可以使用 pass-by-value,并且会使用 pre-allocated 内存。
Pass-by-reference 将尽可能使用 pre-allocated 内存,或分配新内存,无论哪种情况,调用者都将始终看到新的 header/data.
Return-by-value 也将始终正常工作,但它确实必须 re-allocate 每次调用都需要新内存,这可能是不可取的。
“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);
}
//这里是函数
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() 而不是图像
好吧,我对将 Mat 传递给函数并检索它有点困惑 那么让我们说
有什么区别 void GetFrame(Mat& frame)
Vs
void GetFrame(Mat frame)
Vs
Mat GetFrame()
更新:
在哪个版本中,对函数体内框架的更改会导致传递给函数的原始框架发生变化
稍加小心,您可以让所有 3 个版本都工作并做同样的事情,但我会尝试解释细节。
首先,Mat
object 实际上只是一个小的 header,其中包含有关真实数据的元数据(例如,行数和列数),以及指向实际数据。大多数情况下,指针其实是一个智能指针,带引用计数,可以被多个Mat
object共享,最后剩下Mat
[=83=时自动删除] 停止指向它。 (Mat
objects 也可以指向它不拥有的数据,即如果你有一些数据是从不同的 library/API 获得的,并且想重用相同的记忆而不是复制它。)
1。通过参考版本
您的函数的版本 1 可能是最简单的。调用者的 Mat
object 通过引用 复制 ,这显然意味着对 Mat
object 的元数据(包括(智能)指针)将在 return 时对调用者可见。底层数据将明显反映函数所做的任何修改。
2。按值传递版本
在您的函数的版本 2 中(按值传入 Mat
object),Mat
表示的小 header 被复制并传递给函数.复制是浅层的:复制了元数据和(智能)指针,但底层数据由调用者的 Mat
object 和被调用者的 Mat
object 共享。您必须注意的部分是,如果函数修改了复制的 frame
object、 的元数据,这些更改将对调用者不可见 。
因此,例如,如果您传递一个空Mat
,您可能会对结果感到惊讶:首先,复制了空Mat
的meta-data。当函数调用类似 frame.create(newRows, newCols, newType);
的东西时,create
函数将分配一个新的内存块,因为 frame.rows != newRows
、frame.cols != newCols
和 frame.type() != newType
,以及(被调用者的单独复制)frame
元数据已更新,反映了新分配的数据。当函数 returns 时,其 frame
object 将保存对智能指针的唯一引用,因此数据将被自动丢弃。调用者仍然只有一个空的 header.
但是,如果传递给函数的 Mat
object 已经具有正确的维度和类型,frame.create()
将不执行任何操作,这意味着所做的任何修改被调用者对底层数据的访问将对调用者可见。
3。 Return 按值版本
第三个版本与第二个版本类似,不同之处在于函数调用时不是复制 meta-data,而是分配它认为合适的 Mat
,并且meta-data(包括指向底层数据的指针)在 return 时被复制回调用者。基础数据仍然存在并且可供调用者访问。
总结
如果您事先不知道数据的大小和类型,则无法使用pass-by-value。如果你确实知道 size/type,你可以使用 pass-by-value,并且会使用 pre-allocated 内存。
Pass-by-reference 将尽可能使用 pre-allocated 内存,或分配新内存,无论哪种情况,调用者都将始终看到新的 header/data.
Return-by-value 也将始终正常工作,但它确实必须 re-allocate 每次调用都需要新内存,这可能是不可取的。
“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);
}
//这里是函数
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() 而不是图像