Opencv Mat内存管理



内存管理对于映像类至关重要。在opencv中,映像类是cv::Mat,它有一个精细的内存管理方案。假设我已经有了自己的图像类SelfImage:

class SelfImage
{
  public:
    int width_;
    int height_;
    unsigned char *pPixel_;    
};

一开始,我会把所有的图像像素内容放在这个类中:

SelfImage myImage;
myImage.width_ = 300;
myImage.height_ = 200;
myImage.pPixel_ = new [300*200];
for(int i=0; i<300*200; i++)
      myImage.pPixel_[i] = i%200;

那么我的问题是如何以一种非常有效的方式将这个类转换为cv::Mat,我有一个解决方案:

  cv::Mat mat;
    mat.create( myImage.height_, myImage.width_, CV_8UC1);
    mat.data = myImage.pPixel_;

我不知道这是否是一个好的解决方案。如果cv::Mat::create函数也会分配内存,则上述代码存在内存泄漏的危险。有什么想法吗?

编辑我必须明确表示,如果我可以使用cv::Mat::create方法,但与SelfImage类共享内存,那就太好了。原因是定义了一个函数来执行图像类转换作业void TransImageType(const SelfImage &geo_img, cv::Mat &mat)

cv::Mat有一个构造函数,您可以在其中指定用户数据:

Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)

文件中关于data的论点如下:

指向用户数据的指针。获取数据和步骤的矩阵构造函数参数不分配矩阵数据。相反,它们只是初始化指向指定数据的矩阵标头,这意味着不复制任何数据。此操作非常高效,可用于使用OpenCV函数处理外部数据。外部数据不是自动解除分配,所以你应该处理它。

这取决于是否要复制数据。

从你的建议来看,你似乎想分享这些数据。在这种情况下,这是最好的解决方案:

cv::Mat mat(myImage.height_, myImage.width_, CV_8U, myImage.pPixel_);

mat在解除分配时不会释放内存,您必须这样做。

如果要复制数据,请创建一个普通的cv::Mat,稍后再执行std::copy(或@KeillRandor建议的memcpy)。

Mat::create()分配数据(total()*elemSize()字节),并将所分配数据的内部引用计数器初始化为1(除非Mat已经存在,并且具有create()方法中指定的相同大小/类型)。

是的,您的代码会产生内存泄漏,因为当您移动Mat::data指针时,Mat::create()分配的数据会丢失。

正确的方法应该是(在我看来)从myImage.pPixel_mat.data使用memcpy(在调用create()之后)。这可能看起来效率低下,但好的一面是Mat析构函数将处理数据释放。

您可以简单地使用

Mat mat = Mat(myImage.height_, myImage.width_, CV_8UC1, myImage.pPixel_);

这样,就不会复制任何数据。当然,作为代价,你应该注意释放内存。

来自其文档:

[…]相反,它们只是初始化指向指定数据的矩阵头,这意味着没有数据被复制。此操作非常高效,可用于使用OpenCV函数处理外部数据。外部数据不会自动解除分配,因此您应该处理它。

相关内容

  • 没有找到相关文章

最新更新