zoukankan      html  css  js  c++  java
  • cvLoadImage,cvCloneImage的内存泄露问题

    本文转自:

    http://hi.baidu.com/%C3%A8%D1%DB%D3%E3/blog/item/9d947e1b2b05555742a9adfd.html/cmtid/9872c2260129923cc9955905

        针对openCV中,隐蔽的内存泄露,大家需要重视,拯救为数不多的内存,拯救应用程序的速度

        在做项目的过程中,使用OpenCV经常会出现一些内存泄露问题,自己编写的程序出现问题还情有可原,但若是库函数调用和使用时出现,却很令我恼火。花了好长时间和实践的经验告诉我应该客服它。下面把一些检测出的问题进行化解。(可能是水平不够,这些函数使用不当,望高手指点)

        cvLoadImage函数:

        可能大家还觉察不出来,但我深有体会,在程序中这个函数使用一次两次感觉不来,但在处理序列图像循环调用这个函数时,内存泄露的可能让你目瞪口呆!即使你在最后使用cvReleaseImage(&pImg);进行了释放,实验证明:视乎不能成功释放。

        解决方法:

        使用CvvImage类代替。并且使用CvvImage类的Load函数。

        使用过程大概如下:

        //变量定义:

        CvvImage pSrcImg;

        IplImag *pSrcImgCopy ;//使用IplImag变量做个拷贝。毕竟IplImag 类处理方便。

        //获取图像:

        pSrcImg.Load(str);//str为Cstring类型的图像文件名
        pSrcImgCopy = pSrcImg.GetImage();//拷贝出pSrcImg的图像数据。

        //释放内存

        pSrcImg变量不需要每次释放,因为每次Load时是覆盖以前的内存区域。pSrcImgCopy 同样。

    不过在程序结束时要释放,以免产生内存泄露或者别人以为你忘了。

        cvReleaseImage(&pSrcImgCopy );
        pSrcImg.Destroy();

        不过要正确释放pSrcImgCopy 时,声明时必须create下:

        pSrcImgCopy = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3);

        //IMGWIDHT,IMGHEIGHT为图像宽和高。

        cvCloneImage函数:

        这个函数也会出现内存泄露!虽然可以释放,但程序复杂不知道在那里释放,因为它每次拷贝是制作图像的完整拷贝包括头、ROI和数据。不会覆盖以前的内容。每次使用时编译器会分配内存空间。一个752*480大小的图像,每次泄露的内存大约为1M。

        解决方法:

        使用cvCopy函数代替。

        cvCopy(pSrcImg,pImg,NULL);//代替 pImg = cvCloneImage(pSrcImg);

        pImg初始化时必须分配空间,否则上述函数不能执行。

        pImg = cvCreateImage(cvSize(IMGWIDHT,IMGHEIGHT),IPL_DEPTH_8U, 3);

         最近一直在用opencv编写算法程序,但是cvCloneImage、cvCopyImage和cvCloneMat、cvCopyMat这几个函数让我痛苦了好一阵子,程序代码没有任何问题,但是就是得不到结果,在子函数中返回值根本不是我想要的,由于代码挺庞大的,一直没找到问题出在哪里,于是设置一个个断点,通过步步调试,终于发现问题出在了cvCloneImage、cvCopyImage和cvCloneMat、cvCopyMat这几个函数的误用cvCloneImage与cvCloneMat是在赋值的同时会开辟一个新的空间给定义的变量,cvCopyImage与cvCopyMat只复制值,并不会分配一个空间给赋值对象,因此cvCloneImage与cvCloneMat只适合用于变量开始定义,千万不要用在算法处理中间,否则会产生一个新的地址空间,会将赋值对象的指针地址改变,这样会导致整个程序有不可预测的错误发生,最明显的就是你本来想把子函数中的新变量值送回上一层函数,但是由于指针的指向已经改变,所以返回后的值并不会改变。在程序中间进行复制时候建议使用cvCopyImage与cvCopyMat。

        因此当使用opencv函数时候,不同函数实现同一个功能,但是一定要注意他们之间的区别,不然会让你很痛苦,寻找这种错误真的很烦人。

    http://benson.is-programmer.com/posts/21042.html

      戏剧性阶段一:问题的出现 

         最近在使用opencv的时候,发现在图像函数部分,opencv的内存管理存在一定问题。在使用IplImage的图像cvcloneImage()后,调用cvReleaseImage()时,内存并不能全部释放。在实时视频处理程序中,伴随程序运行,很容易造成系统内存消耗殆尽。

    举例来说,看下面的一个最简单代码:

    #include"cv.h"
    #include"highgui.h"
    #pragma comment(lib,"cv.lib")
    #pragma comment(lib,"highgui.lib")
    #pragma comment(lib,"cxcore.lib")

    int _tmain(int argc, _TCHAR* argv[])
    {
     CvCapture* capture = cvCreateCameraCapture(0);
     IplImage* frame;
     cvNamedWindow("ExampleShow",CV_WINDOW_AUTOSIZE);
     while(1)
     {
      frame = cvQueryFrame(capture);
      if(!frame)
       break;
      cvShowImage("ExampleShow",frame);
      char c = cvWaitKey(33);
      if(c == 27)
        break;
     }
     cvReleaseCapture(&capture);
     cvDestroyWindow("ExampleShow");
     return 0;
    }

    运行程序,此时,打开资源管理器,可以看到其所占的“内存使用”一直保持稳定。而如果,简单修改下上面的程序,改变如下:

    #include"cv.h"
    #include"highgui.h"
    #pragma comment(lib,"cv.lib")
    #pragma comment(lib,"highgui.lib")
    #pragma comment(lib,"cxcore.lib")

    int _tmain(int argc, _TCHAR* argv[])
    {
    CvCapture* capture = cvCreateCameraCapture(0);
    IplImage* frame;
    IplImage* clImage;
    cvNamedWindow("ExampleShow",CV_WINDOW_AUTOSIZE);
    cvNamedWindow("Example_Clone",CV_WINDOW_AUTOSIZE);
    while(1)
    {
    frame = cvQueryFrame(capture);
    if(!frame)
    break;
    cvShowImage("ExampleShow",frame);
    clImage = cvCreateImage(cvSize(frame->width,frame->height),frame->depth,frame->nChannels);
    clImage = cvCloneImage(frame);
    cvShowImage("Example_Clone",clImage);
    char c = cvWaitKey(33);
    if(c == 27)
    break;
    cvReleaseImage(&clImage);
    }
    cvReleaseCapture(&capture);
    cvDestroyWindow("ExampleShow");
    cvDestroyWindow("Example_Clone");
    return 0;
    }

    同样,运行程序,打开资源管理器,可以看到“内存使用”中,该程序的内存使用量在不断增加。虽然,程序中对拷贝的图像进行了释放,但是,事实上,却没有看到多少效果!

    虽然发现了这个问题,也在网络上看到相关的这个问题的讨论,试验了几种方法,发现并不work。在此提出问题,继续探索吧。

    戏剧性阶段二:“改良方法”的出现

    在网络上看到,除了cvCloneImage()还有cvLoadImage()也有内存泄露问题。最终的有效解决办法是使用cvCopy()来替换代码中的cvCloneImage(),这时候,不会出现内存不断递增的情况。而cvLoadImage()可以CvvImage类的图像装载函数,然后拷贝到目标图像即可。

    戏剧性三:真正原因的捕获和分析 

    内存无法释放的原因分析:

    今天偶然想起,在观察上面的代码时,发现在其中存在一句:clImage = cvCreateImage(cvSize(frame->width,frame->height),frame->depth,frame->nChannels);

    这句是向内存申请一片空间,用于存放目的图像的空间。造成内存泄露的真正原因是这句。在使用cvCloneImage()的时候,其实是对源图像指针所指向的图像头、数据、ROI等进行了一个完全的拷贝,放在一个新的内存区域,函数结果使得目标图像指向新的内存,而原来用cvCreateImage()所分配的区域没有被正确释放,成为一片“悬挂地址区域”。在后面调用cvReleaseImage()的时候,释放的是后面其所指向的区域。

    因此,要避免这种情况的出现,一种方法是:可以在cvCloneImage()前,先调用cvReleaseImage()来释放之前分配的地址区域。然后执行克隆函数cvCloneImage()操作。也可以在前面不分配空间,直接调用克隆操作。另外一种方法,如果使用cvCopy()函数操作,由于该函数并不会对图像指针分配空间,所以需要先自己用cvCreateImage()分配一段区域,然后调用拷贝函数cvCopy(),来对图像赋值。这样最后释放的是图像指针所指的地址区域。这两种方法都不会出现内存泄露的问题了。

  • 相关阅读:
    C++调用Java的Jar包(带参数)
    SOA创建Form表单
    vs2013 IntelliSense: "const char *" 类型的实参与 "LPCWSTR" 类型的形参不兼容
    idea无法正常使用SVN的解决方法
    关于C语言中print输出问题
    TC怎么在代码中实现选中一个TCCcomponent对象?
    Unity 1.0 中文文档:1 Unity 简介
    Unity(四):使用场景Ⅰ:建立类型映射
    这个世界上没有白干的活
    Unity(三):快速入门
  • 原文地址:https://www.cnblogs.com/xingrun/p/3392687.html
Copyright © 2011-2022 走看看