我正在使用函数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。整个程序可以正常终止,除了内存泄漏。
非常感谢。
答案 0 :(得分:0)
我发现了内存泄漏的原因。原因是:
在MyImage
类构造函数中,我传入了一个IplImage* p
指针,并执行以下操作:
mp = cvCloneImage(p);
其中mp
是IplImage*
类的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
有时会在涉及新线程时给出可能丢失的记忆。所以我监视了系统的内存使用情况。结果显示,当程序重复执行时,不会占用内存。
这就是我发现的。