0

我正在使用函数 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一个成员。如果构造函数将 aIplImage* ppara作为参数,则该成员将使用andp创建内存。如果它以大小、深度和通道作为参数,那么只做。然后析构函数做。该函数的调用如下:cvCreateImage(cvGetSize(ppara), ppara->depth, ppara->nChannels)cvCopy(ppara, p)cvCreateImagecvReleaseImage(&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 位操作系统 fedora 16 上使用 OpenCV 2.3.1。整个程序可以正常终止,但内存泄漏除外。

非常感谢。

4

1 回答 1

0

我发现了为什么会有内存泄漏。原因是:

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

mp = cvCloneImage(p);

wheremp是班级的IplImage*成员。我在创建一个新的类对象后MyImage释放了IplImage*我传入的指针,因为这会创建一些记忆。但是,当它实际上没有新的任何内存时,我释放了类析构函数中的成员指针。它只是指向由 创造的记忆。所以由 创造的记忆并没有被释放。这就是内存泄漏的来源。MyImagecvCloneImage()mpcvCloneImage()cvCloneImage()

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

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

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

这样做之后,肯定丢失和间接丢失的记忆都变成了0,但仍有可能丢失的记忆,valgrind将所有丢失的记录指向cvHaarDetectObjects()来自OpenCV的函数。而且主要是由一些“新线程”问题引起的。因此,我用谷歌搜索了这个问题,发现valgrind有时在涉及新线程时确实可能会丢失记忆。所以我监控了系统的内存使用情况。结果显示,由于程序重复执行,内存使用量没有增加。

这就是我发现的。

于 2012-08-14T15:33:50.100 回答