mans
mans

Reputation: 18168

How to force an opencv image (cv::Mat) to release its memory

I have a class like this:

class MyClass
{
   cv::Mat image;
public:
   init()
   {
        image=imread("test.jpg");
   }
   cv::Mat getImage()
   {
        return image;
    }
   void reset()
   {
      // what should I write here?
    }
}
cv::Mat myImage;

void main()
{
    MyClass myclass;
    myclass.init();
    myImage=myclass.getImage();
    // do something with image;
    myclass.reset();
    // at this point the memory allocated by myclass.image should be released and also myImage should be invalidated (be an empty image).
}

Note: I know that I can make the myImage a local variable and fix the problem, but I want to know how I can release the memory allocated by a cv::Mat even when the reference count is not zero.

image.release() don't release the memory as there is a copy of image (myImage) and I need to make sure that the memory is released even when there is a copy of image.

For people that may complain that it is not a good idea to invalidate the myImage, the class specification says that when reset is called, all images, which was created by class became invalid and if user need the image, they need to clone it before calling reset on the class.

edit1

deallocate doesn't work and it doesn't release memory.

Upvotes: 1

Views: 4151

Answers (3)

bweber
bweber

Reputation: 4082

Maybe the real question is if this design makes sense. The only reason for the user of the class to keep the copy of the previously received Mat object when they call reset is if they still want to work on it. There is no other reason to keep that object. Consequently, invalidating this copy when calling reset is bound to result in a crash. Therefore that behaviour makes no sense. Furthermore it introduces an implicit constraint that the user must know about and that is not communicated through the interface of the class. This is no good design.

Instead, the responsibility for the memory usage is at the side of the class user. They know that if they call getImage and reset a hundred times while keeping all the images, they will consume a lot of memory. And it's their decision, not that of your class.

Instead, you should rather make sure you handle the case when memory is insufficient when creating new Mat object inside your class, so in case no new image can be created this is properly handled and communicated. After all you never know if there is enough memory for your image, even if you release the old image every time.

Upvotes: 0

Uru
Uru

Reputation: 1

getImage has to return a reference Mat& and image.release() in the reset function will do the job.

Upvotes: -1

Micka
Micka

Reputation: 20130

what about this code?

  1. allocate memory to hold your image
  2. create Mat header using that pre-allocated memory
  3. copy loaded image to that memory

This should deactivate the reference counting.

I didn't try it, but I guess it should work (I hope the idea is clear). However, you'll obviously get access errors if there are other Mat references which are still in use!

class MyClass
{
   cv::Mat image;
   unsigned char * imageData; // TODO: set to zero in constructor!
public:
   init()
   {
        cv::Mat tmp = imread("test.jpg");
        // TODO: test if non-zero and release before allocating new memory
        imageData = (unsigned char*) malloc(tmp.cols*tmp.rows*3*sizeof(unsigned char)); // allocate memory for your image
        // TODO: maybe it is possible to get the size of "tmp"'s data directly, which would be much better because of widthStep things, etc. The formula "tmp.cols*tmp.rows*3*sizeof(unsigned char)" might not be correct for all kind of input images!

        // create Mat header that uses present memory
        image=cv::Mat(tmp.rows, tmp.cols, 3, imageData  );

        // copy loaded image to allocated memory:
        tmp.copyTo(image); // here you must be sure that "image" is big enough to hold "tmp"'s data. Otherwise a new Mat will be created.

        // tmp will be cleared automatically
   }
   cv::Mat getImage()
   {
        return image;
   }
   void reset()
   {
      image = cv::Mat();
      free(imageData);
   }
}

Upvotes: 2

Related Questions