- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我已经彻底搜索过,但没有找到直接的答案。
将 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<<"\n\n";
cv::Mat B;
sillyFunc(A,B);
std::cout<<"A = \n"<<A<<"\n\n";
std::cout<<"B = \n"<<B<<"\n\n";
}
显然,A
被更改,即使它是作为 const cv::Mat&
发送的。
这并不让我感到惊讶,因为函数 I2
是 I1
智能指针的简单拷贝,因此 I2
中的任何更改将改变 I1
.
让我感到困惑的是,我不明白发送 cv::Mat
、const cv::Mat
、const cv 之间存在什么实际区别::Mat&
或 cv::Mat&
作为函数的参数。
我知道如何覆盖它(将 Output = Input;
替换为 Output = Input.clone();
将解决问题)但仍然不明白上面提到的区别。
谢谢大家!
最佳答案
都是因为 OpenCV 使用了 Automatic Memory Management .
OpenCV handles all the memory automatically.
First of all,
std::vector
,Mat
, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case ofMat
. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when aMat
instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also theMat::clone
method that creates a full copy of the matrix data.
也就是说,为了让两个 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
。查看 Memory management and reference counting更多详情:
Mat
is a structure that keeps matrix/image characteristics (rows and columns number, data type etc) and a pointer to data. So nothing prevents us from having several instances ofMat
corresponding to the same data. AMat
keeps a reference count that tells if data has to be deallocated when a particular instance ofMat
is destroyed.
cv::Mat
、const cv::Mat
、const cv::Mat&
或cv::的区别Mat&
作为函数的参数:cv::Mat Input
:传递Input
的 header 的拷贝。它的 header 不会在此函数之外更改,但可以在函数内更改。例如:
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
的 header 的拷贝。它的标题不会在函数之外或函数内更改。例如:
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
的 header 的引用。保证 Input
的 header 不会在函数外或函数内更改。例如:
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
header 的引用。 Input
的 header 的更改发生在函数的外部和内部。例如:
void sillyFunc(cv::Mat& Input, cv::Mat& Output){
Input = cv::Mat::ones(4, 4, CV_32F); // totally OK and does change
...
}
P.S.2:我必须指出,在所有四种情况下(cv::Mat
、const cv::Mat
、 const cv::Mat&
或 cv::Mat&
),只有对 Mat 的 header 的访问受到限制,而不是对它指向的数据的访问。例如,您可以在所有四种情况下更改其数据,并且其数据确实会在函数内外发生变化:
/*** 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
}
关于c++ - 使用 "const cv::Mat &"、 "cv::Mat &"、 "cv::Mat"或 "const cv::Mat"作为函数参数的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23468537/
我到处都找了很多,找不到我的问题的答案。我试图从这个线程复制一个文本检测软件(Extracting text OpenCV)但是在代码的末尾有一条消息错误说没有匹配的矩形,即使我已经在上面绘制了一个并
我已经彻底搜索过,但没有找到直接的答案。 将 opencv 矩阵 (cv::Mat) 作为参数传递给函数,我们传递的是智能指针。我们对函数内部的输入矩阵所做的任何更改也会改变函数范围之外的矩阵。 我读
在我的应用程序中,我有一个通过引用接收 cv::Mat 对象的函数。这是函数的声明: void getChains(cv::Mat &img,std::vector &chains,cv::
我正在使用 Qt 编写一个 GUI 程序,并使用 OpenCV 进行一些视频处理。我在主 GUI 线程的标签中显示 OpenCV 进程(在单独的线程中)的结果。 我遇到的问题是 cv::waitKey
Mat a = (Mat_(3,3) = 2 int dims; //! the number of rows and columns or (-1, -1) when the arr
我尝试运行下面的代码,但出现错误。我正在为名为“Mat::at”的 OpenCV 函数创建一个包装器,并尝试使用“G++”将其编译为 Ubuntu Trusty 上的“.so”。我在下面列出了“.cp
我在 C# 中使用 EmguCV,当我想从网络摄像头抓取帧时遇到问题,语句中出现红色下划线: imgOrg = capturecam.QueryFrame(); error: Cannot impli
我正在尝试从另外两个矩阵生成一个 cv::Mat C,以便获得第三个矩阵,该矩阵由通过组合矩阵 A 和 B 的一维点生成的二维点构成。 我的问题是,我尝试的所有操作都只是连接矩阵,并没有真正将每个点与
我用 cv.imread在 python 中读取 png 文件。然后当我使用 cv.imwrite立即保存图像的功能我然后发现图像中的颜色略有变化。我正在尝试在此图像上执行字符识别,而 OCR 在 p
我尝试将 cv::bitwise_not 转换为 double 值的 cv::Mat 矩阵。我申请了 cv::bitwise_not(img, imgtemp); img是0和1的CV_64F数据。但
我正在尝试使用函数 cv.glmnet 找到最佳的 lambda(使用 RIDGE 回归)以预测某些对象的归属类别。所以我使用的代码是: CVGLM<-cv.glmnet(x,y,nfolds=34,
我有这个方法: static void WriteMatVect(const std::string& filename, const std::vector& mats); ... void Fil
下面的转换是我想要做的。 对于源图像中的每个图 block ,我知道每个角的坐标,并且我知道输出图像中每个对应角的坐标,所以我可以调用 cvWarpPerspective 扭曲每个图 block ,然
我必须在C++ / CLI中的托管和非托管代码中都使用OpenCV。 我正在尝试在托管代码中使用Emgu CV来包装OpenCV对象,但是在进行转换时遇到了麻烦。 我该怎么做: Emgu::CV::M
我正在尝试在 cv::Mat 中使用 CV_32FC4,以便它存储 RGBA32 图像。但是当我使用 cv::imwrite 将其保存为 png 文件时,结果文件始终是一个空图像。 例如,我创建了这样
无法在 VS 2017 中设置 OpenCV。我做错了什么?是的,我已将所有其他帖子设为红色。 代码: #include "opencv2/highgui/highgui.hpp" u
我有两个(相同大小,相同类型)cv:Mat 让我们称它们为 A,B。我还有另一个 cv::Mat,它是一个掩码(0 和 1 值或其他值,0 和 255 也适用)让我们称它为 M。 我需要构造一个新的
使用 OpenCV 中实现的 Scalar 类,我不明白这段代码有什么区别: Mat test; test = Scalar::all(0); 还有这个: Mat test = Scalar::all
我对这行代码感到困惑: cv::Mat_::iterator 我知道 Mat_ 属于 cv 命名空间和 vec3b 也。但是之后的最后一个 :: 操作符和 iterator 让我感到困惑!它也属于 c
我想优雅地将 Mat 转换为 Vec3f。目前我是这样做的: Mat line; Vec3f ln; ln[0] = line.
我是一名优秀的程序员,十分优秀!