gpt4 book ai didi

c++ - 使用 "const cv::Mat &"、 "cv::Mat &"、 "cv::Mat"或 "const cv::Mat"作为函数参数的区别?

转载 作者:IT老高 更新时间:2023-10-28 12:45:00 50 4
gpt4 key购买 nike

我已经彻底搜索过,但没有找到直接的答案。

将 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& 发送的。

这并不让我感到惊讶,因为函数 I2I1 智能指针的简单拷贝,因此 I2 中的任何更改将改变 I1.

让我感到困惑的是,我不明白发送 cv::Matconst cv::Matconst 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::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 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::Matconst cv::Matconst cv::Mat&cv::的区别Mat& 作为函数的参数:

  1. 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
    //...
    }
  2. 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
    //...
    }
  3. 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
    ...
    }
  4. 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::Matconst cv::Matconst 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/

50 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com