内存管理对于映像类至关重要。在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函数处理外部数据。外部数据不会自动解除分配,因此您应该处理它。