Reputation: 11773
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
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
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
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
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