I’m using the function cvHaarDetectObjects to do face detection and there is a memory leak checking with valgrind even though I think I freed all the memories. I really don’t know how to fix the memory leak. Here is my code:
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;
}
In the code, MyImage is a wrapper class of IplImage containing IplImage* p as a member. if the constructor takes a IplImage* ppara as parameter, then the member p will create memory using cvCreateImage(cvGetSize(ppara), ppara->depth, ppara->nChannels) and cvCopy(ppara, p). if it takes size,depth and channels as parameter, then only do cvCreateImage. Then the destructor do cvReleaseImage(&p). The function int Detect(MyImage *Img, MyImage **Face) is called like:
IplImage *Temp = cvLoadImage(ImageName);
MyImage* Img = new MyImage(Temp);
if(Temp)
cvReleaseImage(&Temp);
Temp = NULL;
MyImage * Face = NULL;
Detect(Img, &Face);
I released Img and Face in the following code once the operations on them is done. And the memory leak is happened inside the Detect function. I’m using OpenCV 2.3.1 on 64 bit OS fedora 16. The whole program can terminate normally except for the memory leak.
Thanks a lot.
I found out why there is a memory leak. The reason is:
In the
MyImageclass constructor, I passed in aIplImage* ppointer, and do the following:where
mpis aIplImage*member of theMyImageclass. I free theIplImage*pointer that I passed in after creating a newMyImageclass object, sincecvCloneImage()will create some memories. However I free the member pointermpin the class destructor when it actually doesn’t new any memory. It just points to memories that created bycvCloneImage(). So the memories created bycvCloneImage()isn’t freed. This is where the memory leak came from.Thus I do the following in the constructor given a
IplImage* ppassed in as parameter:And free the
mppointer in the class destructor will free the memory that it creates.After doing this, definitely lost and indirectly lost memories are turned to 0, but there are still possibly lost memories, and valgrind points all the lost record to the
cvHaarDetectObjects()function which is from OpenCV. And mostly are caused by some “new threads” issues. Thus I googled this problem and found outvalgrinddoes give possibly lost memories sometimes when new thread is involved. So I monitored the memory usage of the system. The result shows no memory usage building up as the program executed repeatedly.That’s what I found.