c++ 使用“const cv :: Mat”,“cv :: Mat”,“cv :: mat”或“const cv :: mat”作为参数的区别?

我已经彻底搜查,还没有找到一个直截了当的答案。

将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 of 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. 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.

也就是说,为了使两个cv :: Mats指向不同的东西,您需要为它们分配内存。例如,以下将按预期工作:

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 of Mat corresponding to the same data. A Mat keeps a reference count that tells if data has to be deallocated when a particular instance of Mat is destroyed.

发送cv :: Mat,const cv :: Mat,const cv :: Mat&或cv :: Mat&作为函数的参数:

> cv :: Mat输入:传递一个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的头部不会在函数内部或内部更改。例如:

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&输入:传递输入头的引用。对输入头的更改发生在函数之外和函数内。例如:

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

PS2:我必须指出,在所有四种情况(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
}

转载注明原文:c++ 使用“const cv :: Mat”,“cv :: Mat”,“cv :: mat”或“const cv :: mat”作为参数的区别? - 代码日志