简体   繁体   English

使用“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?

I've searched thoroughly and have not found a straightforward answer to this. 我彻底搜查过,并没有找到一个直截了当的答案。

Passing opencv matrices ( cv::Mat ) as arguments to a function, we're passing a smart pointer. 传递opencv矩阵( cv::Mat )作为函数的参数,我们传递一个智能指针。 Any change we do to the input matrix inside the function alters the matrix outside the function scope as well. 我们对函数内部的输入矩阵所做的任何更改也会改变函数范围之外的矩阵。

I read that by passing a matrix as a const reference, it is not altered within the function. 我通过传递矩阵作为const引用来读取它,它不会在函数内被改变。 But a simple example shows it does: 但是一个简单的例子表明它确实:

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";
}

Clearly, A is altered even though it is sent as a const cv::Mat& . 很明显, A被改变了,即使它是作为const cv::Mat&

This does not surprise me as within the function I2 is a simple copy of I1 's smart pointer and thus any change in I2 will alter I1 . 这并不让我感到惊讶,因为在函数I2I1智能指针的简单副本,因此I2任何变化都会改变I1

What does baffle me is that I don't understand what practical difference exists between sending cv::Mat , const cv::Mat , const cv::Mat& or cv::Mat& as arguments to a function. 令我感到困惑的是,我不明白发送cv::Matconst cv::Matconst cv::Mat&cv::Mat&作为函数的参数之间存在什么实际差异。

I know how to override this (replacing Output = Input; with Output = Input.clone(); would solve the problem) but still don't understand the above mentioned difference. 我知道如何覆盖它(替换Output = Input;使用Output = Input.clone();会解决问题)但仍然不理解上面提到的区别。

Thanks guys! 多谢你们!

It's all because OpenCV uses Automatic Memory Management . 这都是因为OpenCV使用自动内存管理

OpenCV handles all the memory automatically. OpenCV自动处理所有内存。

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. 首先,函数和方法使用的std::vectorMat和其他数据结构都有析构函数,可以在需要时释放底层内存缓冲区。 This means that the destructors do not always deallocate the buffers as in case of Mat . 这意味着析构函数并不总是释放缓冲区,就像Mat 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 a Mat instance is copied, no actual data is really copied. 同样,复制Mat实例时,实际上并未复制实际数据。 Instead, the reference counter is incremented to memorize that there is another owner of the same data. 相反,引用计数器递增以记住存在相同数据的另一个所有者。 There is also the Mat::clone method that creates a full copy of the matrix data. 还有Mat::clone方法可以创建矩阵数据的完整副本。

That said, in order to make two cv::Mat s point to different things, you need to allocate memory separately for them. 也就是说,为了让两个cv::Mat指向不同的东西,你需要为它们分别分配内存。 For example, the following will work as expected: 例如,以下内容将按预期工作:

void sillyFunc(const cv::Mat& Input, cv::Mat& Output){
    Output = Input.clone(); // Input, Output now have seperate memory
    Output += 1;
}

PS : cv::Mat contains an int* refcount that points to the reference counter. PScv::Mat包含指向引用计数器的int* refcount计数。 Check out Memory management and reference counting for more details: 查看内存管理和引用计数以获取更多详细信息:

Mat is a structure that keeps matrix/image characteristics (rows and columns number, data type etc) and a pointer to data. Mat是一种保持矩阵/图像特征(行和列数,数据类型等)和指向数据的指针的结构。 So nothing prevents us from having several instances of Mat corresponding to the same data. 因此,没有什么能阻止我们将Mat几个实例对应于相同的数据。 A Mat keeps a reference count that tells if data has to be deallocated when a particular instance of Mat is destroyed. Mat保留一个引用计数,告知在销毁Mat的特定实例时是否必须释放数据。


Differences between sending cv::Mat , const cv::Mat , const cv::Mat& or cv::Mat& as arguments to a function: 发送cv::Matconst cv::Matconst cv::Mat&cv::Mat&作为函数的参数之间的差异:

  1. cv::Mat Input : pass a copy of Input 's header. cv::Mat Input :传递Input头的副本。 Its header will not be changed outside of this function, but can be changed within the function. 它的标题不会在此函数之外更改,但可以在函数内更改。 For example: 例如:

     void sillyFunc(cv::Mat Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // OK, but only changed within the function //... } 
  2. const cv::Mat Input : pass a copy of Input 's header. const cv::Mat Input :传递Input头的副本。 Its header will not be changed outside of or within the function. 它的标题不会在函数之外或之内更改。 For example: 例如:

     void sillyFunc(const cv::Mat Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // Error, even when changing within the function //... } 
  3. const cv::Mat& Input : pass a reference of Input 's header. const cv::Mat& Input :传递Input头的引用。 Guarantees that Input 's header will not be changed outside of or within the function. 保证Input的标题不会在函数之外或之内更改。 For example: 例如:

     void sillyFunc(const cv::Mat& Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // Error when trying to change the header ... } 
  4. cv::Mat& Input : pass a reference of Input 's header. cv::Mat& Input :传递Input头的引用。 Changes to Input 's header happen outside of and within the function. Input的标题的更改发生在函数之外和之内。 For example: 例如:

     void sillyFunc(cv::Mat& Input, cv::Mat& Output){ Input = cv::Mat::ones(4, 4, CV_32F); // totally OK and does change ... } 

PS2 : I must point out that, in all the four situations ( cv::Mat , const cv::Mat , const cv::Mat& or cv::Mat& ), only the access to the Mat's header is restrained, not to the data it points to. PS2 :我必须指出,在所有四种情况下( cv::Matconst cv::Matconst cv::Mat&cv::Mat& ),只限制对Mat的标题的访问,而不是它指向的数据。 For example, you can change its data in all the four situations and its data will indeed change outside of and within the function: 例如,您可以在所有四种情况下更改其数据,并且其数据确实会在函数之外和之内更改:

/*** 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
}

当您将智能指针作为引用传递时,理论上可以节省一些处理时间,因为不会调用智能指针的复制构造函数。

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

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