如何强制opencv图像(cv :: Mat)释放其内存

时间:2016-03-31 08:54:58

标签: c++ opencv memory-management

我有一个这样的课程:

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).
}

注意:我知道我可以使myImage成为局部变量并解决问题,但我想知道如何释放cv :: Mat分配的内存,即使引用计数不为零。

image.release()不要释放内存,因为有一个图像副本(myImage),我需要确保即使有图像副本也会释放内存。

对于那些可能会抱怨使myImage无效的人,类规范说当调用reset时,由类创建的所有图像都变得无效,如果用户需要图像,他们需要在调用类重置之前克隆它。

EDIT1

deallocate不起作用,也不会释放内存。

3 个答案:

答案 0 :(得分:2)

这段代码怎么样?

  1. 分配内存以保存您的图片
  2. 使用预先分配的内存创建Mat标头
  3. 将加载的图像复制到该内存
  4. 这应该停用引用计数。

    我没有尝试过,但我想它应该有用(我希望这个想法很明确)。但是,如果还有其他Mat引用仍在使用中,您显然会遇到访问错误!

    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);
       }
    }
    

答案 1 :(得分:0)

也许真正的问题是这个设计是否有意义。该类用户在调用Mat时保留以前收到的reset对象副本的唯一原因是他们仍然希望对其进行操作。保留该对象没有其他理由。因此,在调用reset时使此副本无效必然会导致崩溃。因此,这种行为毫无意义。此外,它引入了一个隐含的约束,用户必须知道并且不通过类的接口进行通信。这不是一个好的设计。

相反,内存使用的责任在于类用户。他们知道如果他们在保留所有图像的同时调用getImagereset一百次,他们将消耗大量内存。这是他们的决定,而不是你班级的决定。

相反,在类中创建新的Mat对象时,您应该确保处理内存不足时的情况,因此如果无法创建新图像,则可以正确处理和通信。毕竟你永远不知道你的图像是否有足够的内存,即使你每次都发布旧图像。

答案 2 :(得分:-1)

getImage必须返回参考Mat&和重置功能中的image.release()将完成这项工作。