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。コンストラクターがIplImage* pparaas パラメーターを取る場合、メンバーは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ビットOSのfedora 16でOpenCV 2.3.1を使用しています。メモリリークを除いて、プログラム全体が正常に終了します。

どうもありがとう。

4

1 に答える 1

0

メモリリークの原因がわかりました。その理由は:

MyImageクラス コンストラクターでポインターを渡し、IplImage* p次の操作を行います。

mp = cvCloneImage(p);

はクラスmpIplImage*メンバーです。新しいクラス オブジェクトを作成した後、渡し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 に答える