feelfree
feelfree

Reputation: 11773

Opencv Mat memory management

Memory management is essential for an image class. In opencv, the image class is cv::Mat, which has a delicate memory management scheme. Suppose I already have my own image class SelfImage:

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

At the beginning, I will put all the image pixel contents to this class:

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;

Then my question is how I can transform this class to cv::Mat in a very efficient way, one solution I have is:

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

I do not know whether this is a good solution. If cv::Mat::create function will also allocate memory,then the above codes have the danger of memory leak. Any ideas?

EDIT I have to make it clear that it would be nice if I can use cv::Mat::create method but share the memory with SelfImage class.The reason is that a function is defined to perfom the image class transform job void TransImageType(const SelfImage &geo_img, cv::Mat &mat);

Upvotes: 4

Views: 14369

Answers (4)

herohuyongtao
herohuyongtao

Reputation: 50717

You can simply use

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

In this way, no data is copied. And, of course, as the price, you should take care of releasing the memory.

From its doc:

[...] Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.

Upvotes: 1

Яois
Яois

Reputation: 3858

Mat::create() allocates data (total()*elemSize() bytes) and initializes the internal reference counter of the allocated data to 1, (except when the Mat already existed and had the same size/type specified in the create() method).

And yes, your code produces a memory leak since the data allocated by Mat::create() is lost when you move the Mat::data pointer.

The proper way to do it should be (in my opinion) by using memcpy from myImage.pPixel_ to mat.data (after calling create()). This may seem inefficient, but the good side is that the Mat destructor will handle the data deallocation.

Upvotes: 1

ChronoTrigger
ChronoTrigger

Reputation: 8617

It depends on if you want to copy the data.

From your suggestion, it seems you want to share the data. In that case, this is the best solution:

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

The mat will not release the memory when it is deallocated, you will have to do it.

If you want to copy data, create a normal cv::Mat and do std::copy later (or memcpy as @KeillRandor suggested).

Upvotes: 2

BConic
BConic

Reputation: 8990

cv::Mat has a constructor where you can specify user data:

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

The documentation says the following about the data argument:

Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied. This operation is very efficient and can be used to process external data using OpenCV functions. The external data is not automatically deallocated, so you should take care of it.

Upvotes: 13

Related Questions