2012-08-09 61 views
0

我正在使用函數cvHaarDetectObjects進行人臉檢測,並且使用valgrind進行內存泄漏檢查,即使我認爲我釋放了所有內存。我真的不知道如何解決內存泄漏問題。這是我的代碼:cvHaarDetectObjects內存泄漏

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* p作爲成員的包裝類的IplImage的。如果構造函數使用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); 

我發佈圖和臉部下面的代碼,一旦對它們的操作完成。內存泄漏發生在Detect功能內部。我在64位操作系統的Fedora 16上使用OpenCV 2.3.1。除了內存泄漏外,整個程序可以正常終止。

非常感謝。

回答

0

我發現了爲什麼有內存泄漏。其原因是:

MyImage類的構造函數,我通過在IplImage* p指針,並執行以下操作:

mp = cvCloneImage(p); 

其中mpMyImage類的IplImage*成員。我在創建一個新的MyImage類對象後釋放了我通過的IplImage*指針,因爲cvCloneImage()將創建一些記憶。但是,當它實際上並沒有新的內存時,我在類析構函數中釋放了成員指針mp。它只是指向由cvCloneImage()創建的記憶。所以cvCloneImage()創建的記憶不會被釋放。這是內存泄漏的來源。

因此我做了以下給出傳遞作爲參數IplImage* p構造:

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

並釋放mp指針類析構函數,它創建將釋放內存。

這樣做後,絕對丟失和間接丟失的內存變爲0,但仍有可能丟失內存,valgrind將所有丟失的記錄指向OpenCV的cvHaarDetectObjects()函數。主要是由一些「新線程」問題引起的。因此,我GOOGLE了這個問題,發現valgrind確實有可能在新線程涉及時丟失記憶。所以我監視了系統的內存使用情況。結果顯示隨着程序重複執行,沒有內存使用增加。

這就是我發現的。