cvHaarDetectObjects内存泄漏

时间:2012-08-09 14:26:23

标签: opencv memory-leaks face-detection

我正在使用函数cvHaarDetectObjects进行面部检测,并且使用valgrind进行内存泄漏检查,即使我认为我释放了所有的记忆。我真的不知道如何修复内存泄漏。这是我的代码:

int Detect(MyImage* Img,MyImage **Face)
{

  Char* Cascade_name = new Char[1024];
  strcpy(Cascade_name,"/usr/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml");

    // Create memory for calculations
    CvMemStorage* Storage = 0;


    // Create a new Haar classifier
    CvHaarClassifierCascade* Cascade = 0;

    int Scale = 1;

    // Create two points to represent the face locations
    CvPoint pt1, pt2;
    int Loop;

    // Load the HaarClassifierCascade
    Cascade = (CvHaarClassifierCascade*)cvLoad( Cascade_name, 0, 0, 0 );

    // Check whether the cascade has loaded successfully. Else report and error and quit
    if( !Cascade )
    {
        fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
        exit(0);
    }

    // Allocate the memory storage
    Storage = cvCreateMemStorage(0);

    // Clear the memory storage which was used before
    cvClearMemStorage( Storage );

    // Find whether the cascade is loaded, to find the faces. If yes, then:
    if( Cascade )
    {
        // There can be more than one face in an image. So create a growable sequence of faces.
        // Detect the objects and store them in the sequence

      CvSeq* Faces = cvHaarDetectObjects( Img->Image(), Cascade, Storage,
                                            1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
                                            cvSize(40, 40) );

        int MaxWidth = 0;
        int MaxHeight = 0;
        if(Faces->total == 0)
        {
           cout<<"There is no face."<<endl;
           return 1;
        }


       //just get the first face 
        for( Loop = 0; Loop <1; Loop++ )
        {
           // Create a new rectangle for drawing the face
            CvRect* Rect = (CvRect*)cvGetSeqElem( Faces, Loop );

            // Find the dimensions of the face,and scale it if necessary
            pt1.x = Rect->x*Scale;
            pt2.x = (Rect->x+Rect->width)*Scale;
            if(Rect->width>MaxWidth) MaxWidth = Rect->width;
            pt1.y = Rect->y*Scale;
            pt2.y = (Rect->y+Rect->height)*Scale;
            if(Rect->height>MaxHeight) MaxHeight = Rect->height;
            cvSetImageROI( Img->Image(), *Rect );

            MyImage* Dest = new MyImage(cvGetSize(Img->Image()),IPL_DEPTH_8U, 1); 

            cvCvtColor( Img->Image(), Dest->Image(), CV_RGB2GRAY );

            MyImage* Equalized = new MyImage(cvGetSize(Dest->Image()), IPL_DEPTH_8U, 1);

            // Perform histogram equalization
            cvEqualizeHist( Dest->Image(), Equalized->Image());
            (*Face) = new MyImage(Equalized->Image());

            if(Equalized)
               delete Equalized;
            Equalized = NULL;

            if(Dest)
               delete Dest;
            Dest = NULL;

            cvResetImageROI(Img->Image());

        }

        if(Cascade)
        {
           cvReleaseHaarClassifierCascade( &Cascade ); 
           delete Cascade;
           Cascade = NULL;
        }


        if(Storage)
        {
           cvClearMemStorage(Storage);

           cvReleaseMemStorage(&Storage);
           delete Storage;
           Storage = NULL;
        }
        if(Cascade_name)
           delete [] Cascade_name;
        Cascade_name = NULL;
    return 0;
}

在代码中,MyImage是IplImage的包装类,包含IplImage* p作为成员。如果构造函数采用IplImage* ppara作为参数,则成员p将使用cvCreateImage(cvGetSize(ppara), ppara->depth, ppara->nChannels)cvCopy(ppara, p)创建内存。如果它需要大小,深度和通道作为参数,那么只做cvCreateImage。然后析构函数执行cvReleaseImage(&p)。函数int Detect(MyImage *Img, MyImage **Face)被称为:

    IplImage *Temp = cvLoadImage(ImageName);

    MyImage* Img = new MyImage(Temp);
    if(Temp)
       cvReleaseImage(&Temp);
    Temp = NULL;     
    MyImage * Face = NULL;      
    Detect(Img, &Face);

一旦完成对它们的操作,我就在下面的代码中发布了Img和Face。内存泄漏发生在Detect函数内部。我在64位OS fedora 16上使用OpenCV 2.3.1。整个程序可以正常终止,除了内存泄漏。

非常感谢。

1 个答案:

答案 0 :(得分:0)

我发现了内存泄漏的原因。原因是:

MyImage类构造函数中,我传入了一个IplImage* p指针,并执行以下操作:

mp = cvCloneImage(p);

其中mpIplImage*类的MyImage成员。在创建新的IplImage*类对象后,我释放了我传入的MyImage指针,因为cvCloneImage()会创建一些记忆。但是,当它实际上没有新的任何内存时,我释放类析构函数中的成员指针mp。它只是指向由cvCloneImage()创建的记忆。因此cvCloneImage()创建的记忆不会被释放。这是内存泄漏的来源。

因此,我在构造函数中执行以下操作,并将IplImage* p作为参数传入:

mp = cvCreateImage(cvGetSize(p), p->depth, p->nChannels);
cvCopy(p, mp);

释放类析构函数中的mp指针将释放它创建的内存。

在这样做之后,绝对丢失和间接丢失的记忆被转为0,但仍然可能丢失记忆,并且valgrind将所有丢失的记录指向来自OpenCV的cvHaarDetectObjects()功能。而且大多是由一些“新线程”问题引起的。因此我搜索了这个问题并发现valgrind有时会在涉及新线程时给出可能丢失的记忆。所以我监视了系统的内存使用情况。结果显示,当程序重复执行时,不会占用内存。

这就是我发现的。