首页 文章

Opencv Mat内存管理

提问于
浏览
3

内存管理对于图像类至关重要 . 在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 函数也会分配内存,那么上面的代码就有内存泄漏的危险 . 有任何想法吗?

EDIT 我必须说清楚,如果我可以使用 cv::Mat::create 方法但是与 SelfImage 类共享内存会很好 . 原因是定义了一个函数来执行图像类转换作业 void TransImageType(const SelfImage &geo_img, cv::Mat &mat) ;

4 回答

  • 6

    cv::Mat has a constructor您可以在其中指定用户数据:

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

    文档说明了关于 data 参数的以下内容:

    指向用户数据的指针 . 采用数据和步骤参数的矩阵构造函数不分配矩阵数据 . 相反,它们只是初始化指向指定数据的矩阵标头,这意味着不会复制任何数据 . 此操作非常有效,可用于使用OpenCV函数处理外部数据 . 外部数据不会自动解除分配,因此您应该对其进行处理 .

  • 1

    这取决于您是否要复制数据 .

    根据您的建议,您似乎想要共享数据 . 在这种情况下,这是最好的解决方案:

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

    mat 在取消分配时不会释放内存,您必须这样做 .

    如果要复制数据,请创建正常的 cv::Mat 并稍后执行 std::copy (或建议使用 memcpy 作为@KeillRandor) .

  • 1

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

    是的,你的代码 produces a memory leak ,因为移动 Mat::data 指针时 Mat::create() 分配的数据会丢失 .

    正确的做法应该是(在我看来)使用 memcpymyImage.pPixel_mat.data (在致电 create() 之后) . 这似乎效率低下,但好的一面是 Mat 析构函数将处理数据释放 .

  • 1

    你可以简单地使用

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

    这样,就不会复制任何数据 . 当然,作为价格,你应该注意释放记忆 .

    来自doc

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

相关问题