C++ OpenCV cv::Mat 的深拷贝

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21659496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:45:39  来源:igfitidea点击:

Deep Copy of OpenCV cv::Mat

c++opencvdeep-copy

提问by flyinggip

The behaviour of copying cv::Matis confusing me.

抄袭的行为cv::Mat让我很困惑。

I understand from the documentation that Mat::copyTo()is deep copy while the assignment operator is not. My questions:

我从文档中了解到,Mat::copyTo()赋值运算符不是深拷贝。我的问题:

  1. what should I do to return a cv::Matfrom a function, such as: cv::Mat func()?

  2. According to the documentation, if I return a cv::Matit'll have no use, because after the function returns the local copy of the cv::Matin that function will be destroyed and therefore the one accepting the returned value outside the function should be pointing to some random address. The weird thing is that (most of times) it works correctly. For example, the following works:

    cv::Mat CopyOneImage(const cv::Mat& orgImage)
    {
    
        cv::Mat image;
        orgImage.copyTo(image);
        return image;
    
    }
    
    int main()
    {
    
        std::string orgImgName("a.jpg");        
        cv::Mat orgImage;
        orgImage = cv::imread(orgImgName);
    
        cv::Mat aCopy;
        aCopy = CopyOneImage(orgImage);
    
        return 1;
    }
    
  1. 我应该怎么做才能cv::Mat从函数返回 a ,例如:cv::Mat func()

  2. 根据文档,如果我返回 acv::Mat它将没有用,因为在函数返回之后,该函数中的本地副本cv::Mat将被销毁,因此在函数外部接受返回值的那个应该指向某个随机地址. 奇怪的是(大多数时候)它可以正常工作。例如,以下工作:

    cv::Mat CopyOneImage(const cv::Mat& orgImage)
    {
    
        cv::Mat image;
        orgImage.copyTo(image);
        return image;
    
    }
    
    int main()
    {
    
        std::string orgImgName("a.jpg");        
        cv::Mat orgImage;
        orgImage = cv::imread(orgImgName);
    
        cv::Mat aCopy;
        aCopy = CopyOneImage(orgImage);
    
        return 1;
    }
    

But why? It's not a deep copy.

但为什么?这不是深拷贝。

Question 3. And also sometimes the assignment operator seems to be deep copy, too:

问题 3. 有时赋值运算符似乎也是深拷贝:

    int main()
    {

        std::string orgImgName("a.jpg");        
        cv::Mat orgImage;
        orgImage = cv::imread(orgImgName);

        cv::Mat aCopy;
        orgImage.copyTo(aCopy);

        cv::Mat copyCopy1;
        copyCopy1 = aCopy;

        cv::namedWindow("smallTest", 1);
        cv::imshow("smallTest", copyCopy1);
        uchar key = (uchar)cv::waitKey();

        cv::Mat orgImage2 = cv::imread("b.jpg");
        orgImage2.copyTo(aCopy);

        cv::imshow("smallTest", copyCopy1);
        return 1;
    }

Then the two displays shows the same image, a.jpg. Why? And some other times it doesn't work. (The original code is too long but it can be also simplified to the above case). In those times the assignment operator seem to be actually 'shallow' copying. Why?

然后两个显示器显示相同的图像,a.jpg。为什么?有时它不起作用。(原代码太长但也可以简化为上述情况)。在那些时候,赋值运算符似乎实际上是“浅”复制。为什么?

Thanks a lot!

非常感谢!

回答by Andrey Smorodov

I think, that using assignment is not the best way of matrix copying. If you want new full copy of the matrix, use:

我认为,使用赋值并不是矩阵复制的最佳方式。如果您想要矩阵的新完整副本,请使用:

Mat a=b.clone(); 

If you want copy matrix for replace the data from another matrix (for avoid memory reallocation) use:

如果您想复制矩阵来替换另一个矩阵中的数据(以避免内存重新分配),请使用:

Mat a(b.size(),b.type());
b.copyTo(a);

When you assign one matrix to another, the counter of references of smart pointer to matrix data increased by one, when you release matrix (it can be done implicitly when leave code block) it decreases by one. When it becomes equal zero the allocated memory deallocated.

当您将一个矩阵分配给另一个矩阵时,指向矩阵数据的智能指针的引用计数器增加一,当您释放矩阵时(可以在离开代码块时隐式完成)它减少一。当它变为零时,分配的内存被释放。

If you want get result from the function use references it is faster:

如果你想从函数使用引用中得到结果,它会更快:

void Func(Mat& input,Mat& output)
{
 somefunc(input,output);
}

int main(void)
{
...
  Mat a=Mat(.....);
  Mat b=Mat(.....);
  Func(a,b);
...
}

回答by Indika Pathi

I've been using OpenCV for a while now and the cv::Matconfused me too, so I did some reading.

我已经使用 OpenCV 有一段时间了,cv::Mat我也很困惑,所以我做了一些阅读。

cv::Matis a header that points to a *datapointer which holds the actual image data. It also implements reference counting. it holds the number of cv::Matheaders currently pointing to that *datapointer. So when you do a regular copy such as:

cv::Mat*data指向保存实际图像数据的指针的标头。它还实现了引用计数。它保存cv::Mat当前指向该*data指针的标头数。因此,当您进行常规复制时,例如:

cv::Mat b; 
cv::Mat a = b;

awill point to b's data and the reference count for it will be incremented. At the same time, the reference count for the data previously pointed to by bwill be decremented (and the memory will be freed if it is 0 after decrementing).

a将指向b的数据,并且它的引用计数将递增。同时,之前指向的数据的引用计数b会递减(递减后为0则释放内​​存)。

Question 1: It depends on your program. Please refer to this question for more details: is-cvmat-class-flawed-by-design

问题 1:这取决于您的程序。有关更多详细信息,请参阅此问题:is-cvmat-class-flawed-by-design

Question 2: the function returns by value. That means return imagewill copy the Mat and increase the ref count(now ref_count = 2) and return the new Mat. When the function ends, the image will be destroyed and ref_count will be reduced by one. But the memory will not be freed since the ref_countis not 0. So the returned cv::Matis not pointing to random memory location.

问题2:函数按值返回。这意味着return image将复制 Mat 并增加引用计数(现在ref_count = 2)并返回新的 Mat。当函数结束时,图像将被销毁并且 ref_count 将减一。但是内存不会被释放,因为ref_count它不是 0。所以返回cv::Mat的不是指向随机内存位置。

Question 3: A similar thing happens. When you say orgImage2.copyTo(aCopy);The ref_count for the data pointed to by aCopywill be decreased. Then new memory is allocated to store the new data that will be copied. So That is why copyCopy1was not modified when you did this.

问题3:类似的事情发生了。当您说orgImage2.copyTo(aCopy);指向的数据的 ref_countaCopy将减少。然后分配新的内存来存储将要复制的新数据。所以这就是为什么copyCopy1当你这样做时没有被修改。

回答by user3102241

Take a look at c++11 std::shared_ptreffectively works in the same way, by using a reference counter cv::Mat cleverly remembers every time the pointer is referenced, once the count reaches 0 it is automatically released i.e. memory is deallocated and cv::Mat is no longer available. This is effectively a "shallow copy" and saves resources in allocating/deallocating large amounts of memory.

看看 c++11 std::shared_ptr以同样的方式有效地工作,通过使用引用计数器 cv::Mat 巧妙地记住每次指针被引用时,一旦计数达到 0,它就会自动释放,即内存被释放并且 cv::Mat 不再可用。这实际上是一个“浅拷贝”,并在分配/取消分配大量内存时节省了资源。

On the other hand cv::Mat::clone will provide a "deep copy" that allocates a whole new block of memory for the matrix to reside in, this can be useful if you are making transformations to an image that you may want to undo however, more memory allocating/deallocating increases the amount of resources required.

另一方面, cv::Mat::clone 将提供一个“深拷贝”,为矩阵分配一个全新的内存块,如果您正在对您可能想要的图像进行转换,这可能很有用然而,撤消更多的内存分配/解除分配会增加所需的资源量。

Hope this helps someone.

希望这可以帮助某人。