使用"const cv::Mat &"、"cv::Mat &"、"cv::Mat"或"const cv::Mat"作为函数参数有什么区别?
Differences of using "const cv::Mat &", "cv::Mat &", "cv::Mat" or "const cv::Mat" as function parameters?
我已经彻底搜索过了,还没有找到一个直接的答案。
传递opencv矩阵(cv::Mat
)作为函数的参数,我们传递了一个智能指针。我们对函数内部的输入矩阵所做的任何改变也会改变函数作用域外的矩阵。
我读到,通过传递矩阵作为const引用,它不会在函数内改变。但是有一个简单的例子可以说明:
void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
Output = Input;
Output += 1;
}
int main( int argc, char** argv ){
cv::Mat A = cv::Mat::ones(3,3,CV_8U);
std::cout<<"A = n"<<A<<"nn";
cv::Mat B;
sillyFunc(A,B);
std::cout<<"A = n"<<A<<"nn";
std::cout<<"B = n"<<B<<"nn";
}
显然,即使作为const cv::Mat&
发送,A
也被改变了。
这并不让我感到惊讶,因为在函数中I2
是I1
的智能指针的简单副本,因此I2
的任何更改都会改变I1
。
让我困惑的是,我不明白发送cv::Mat
, const cv::Mat
, const cv::Mat&
或cv::Mat&
作为函数的参数之间存在什么实际差异。
我知道如何覆盖这个(用Output = Input.clone();
替换Output = Input;
将解决问题),但仍然不理解上面提到的差异。
谢谢你们了!
这都是因为OpenCV使用了自动内存管理。
OpenCV自动处理所有内存
首先,
std::vector
、Mat
和其他函数和方法使用的数据结构都有析构函数,在需要时释放底层内存缓冲区。这意味着析构函数并不总是像Mat
那样释放缓冲区。他们考虑到可能的数据共享。析构函数减少与矩阵数据缓冲区相关联的引用计数器。当且仅当引用计数器达到零时,即没有其他结构引用相同的缓冲区时,缓冲区被释放。类似地,当复制Mat
实例时,没有实际的数据被真正复制。相反,引用计数器是递增的,以记住同一数据的另一个所有者。还有Mat::clone
方法可以创建矩阵数据的完整副本。
也就是说,为了使两个cv::Mat
指向不同的东西,您需要分别为它们分配内存。例如,以下命令将按预期工作:
void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
Output = Input.clone(); // Input, Output now have seperate memory
Output += 1;
}
p。S: cv::Mat
包含一个指向引用计数器的int* refcount
。查看内存管理和引用计数了解更多细节:
Mat
是一个保持矩阵/图像特征(行和列数,数据类型等)和指向数据的指针的结构。因此,没有什么可以阻止我们有几个Mat
实例对应于相同的数据。Mat
保持一个引用计数,该计数告诉当Mat
的特定实例被销毁时,数据是否必须被释放。
发送cv::Mat
, const cv::Mat
, const cv::Mat&
, cv::Mat&
作为函数参数的区别:
cv::Mat Input
:传递Input
报头的副本。它的头文件不能在函数外部修改,但可以在函数内部修改。例如:void sillyFunc(cv::Mat Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // OK, but only changed within the function //... }
const cv::Mat Input
:传递Input
头文件的副本。它的头文件不会在函数外部或函数内部被修改。例如:void sillyFunc(const cv::Mat Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // Error, even when changing within the function //... }
const cv::Mat& Input
:传递Input
报头的引用。保证Input
的头不会在函数外部或函数内部被更改。例如:void sillyFunc(const cv::Mat& Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // Error when trying to change the header ... }
cv::Mat& Input
:传递Input
报头的引用。对Input
头的更改发生在函数外部和内部。例如:void sillyFunc(cv::Mat& Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // totally OK and does change ... }
注:2:我必须指出,在所有四种情况下(cv::Mat
, const cv::Mat
, const cv::Mat&
或cv::Mat&
),只有对Mat头的访问受到限制,而不是对它指向的数据。例如,您可以在所有四种情况下更改它的数据,并且它的数据确实会在函数外部和内部更改:
/*** will work for all the four situations ***/
//void sillyFunc(cv::Mat Input){
//void sillyFunc(const cv::Mat Input){
//void sillyFunc(const cv::Mat &Input){
void sillyFunc(cv::Mat &Input){
Input.data[0] = 5; // its data will be changed here
}
- 将CHW格式的浮点向量转换为cv::Mat
- C++:从GPU内存(cudaMemcpy2D)获取BGR图像(cv::Mat)
- 选择基于另一个垫子的非零像素的cv::Mat的一部分?
- 将 cv::mat 转换为 QImage
- 将 cv::Mat 转换为 std::vector 的通用函数
- 在 QML VideoOutput 中将 cv::mat 显示为 QVideoFrame
- 如何将 cv::Mat 转换为 vtkImageData?
- 如何将 vtkImageData 转换为 cv::Mat?
- 如何总结所有cv::Mat元素
- Qt-工作线程崩溃时将cv::Mat转换为QImage
- 在 cv::Mat 中生成 2D 坐标网格
- 将 cv::Mat 转换为无符号的 int 像素
- OpenCV 分段错误(核心转储)在使用 cv::Mat::at 时
- 如何将多个 cv::Mat 从 c++ dll 传递到 opencvsharp Mat c#?
- 如何在不复制数据的情况下将 cv::Mat 转换为 2d 标准::矢量
- 如何使用 (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors)
- 从数组创建 Mat 时,'cv::Mat' 和 'int' 类型不兼容
- 如何将 cv::mat 对象从 python 模块传递到 c++ 函数并返回返回的 cv::mat 类型为对象?
- 移动语义和 cv::Mat
- OpenCV 错误:断言在 cv::Mat 行 522 中失败