www.pudn.com > PCA_faceRec_V2.rar > HaarDetecting.cpp


#include "stdafx.h" 
#include "HaarDetecting.h" 
 
#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) 
#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) 
/////////////////////////////////////////////////////////////////////////////////////////// 
BOOL IntegralImage(BYTE* pbyteSrcImg, int SAT[], int RSAT[],double SSAT[],int W,int H) 
{ 
	assert(pbyteSrcImg != NULL); 
		unsigned char* pixel=NULL;  
	    unsigned char* p_orignal=NULL; 	 	   
        pixel=pbyteSrcImg; 
	   //p_orignal=pixel;	    	 
	         for(int j=0;j=0;h--) 
            for(int count=0;count<=j-h&&countbmiHeader.biSize=sizeof(BITMAPINFOHEADER);  
    pInfo->bmiHeader.biWidth=nWidth;  
    pInfo->bmiHeader.biHeight=nHeight;  
    pInfo->bmiHeader.biPlanes=1;  
    pInfo->bmiHeader.biBitCount=8;  
    pInfo->bmiHeader.biCompression=BI_RGB;  
    pInfo->bmiHeader.biSizeImage=imageSize;  
    pInfo->bmiHeader.biXPelsPerMeter=0;  
    pInfo->bmiHeader.biYPelsPerMeter=0;  
    pInfo->bmiHeader.biClrUsed=0;  
    pInfo->bmiHeader.biClrImportant=0;  
 
  	for(i=0;i<256;i++) 
	{ 
		pInfo->bmiColors[i].rgbBlue=i; 
		pInfo->bmiColors[i].rgbGreen=i; 
		pInfo->bmiColors[i].rgbRed=i; 
		pInfo->bmiColors[i].rgbReserved=0; 
	} 
 
	FILE* mFile = NULL; 
	mFile=fopen(pszFileName,"wb"); 
	if(mFile == NULL) 
	{ 
		AfxMessageBox(_T("the file is not opened!")); 
		return; 
	} 
	fwrite((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER),1,mFile); 
    fwrite(pInfo,sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD),1, mFile); 
	fwrite(saveImage,sizeof(BYTE),imageSize,mFile);  
	fclose(mFile); 
	free(pInfo); 
	delete[]saveImage; 
} 
 
 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
BOOL LoadStageClassifier(const char* filename, StageClassifier* stageClassifier) 
{ 
	if( NULL == filename || NULL == stageClassifier ) 
		return FALSE;		 
	FILE* file = NULL; 
	file = fopen(filename, "r"); 
	if( !file ) 
		return FALSE; 
	int count = 0; 
	float threshold = 0.0F;	 
	fscanf( file, "%f", &threshold ); 
	fscanf( file, "%d", &count ); 
	if(count > 0) 
	{ 
		stageClassifier->count = count; 
		stageClassifier->threshold = threshold; 
		stageClassifier->classifier = new HaarClassifier[count]; 
 
		for(int i = 0; i < stageClassifier->count; i++) 
		{ 
			HaarClassifier* classifier = stageClassifier->classifier + i; 
			//指针偏移 
			R_Feature r_feature; 
			fscanf( file, "%d %d %d %d %d", &r_feature.i, 
				    &r_feature.x,&r_feature.y, 
					&r_feature.w,&r_feature.h); 
			change_R_Feature2HaarFeature(r_feature,classifier->haarfeature); 
			fscanf( file, "%f %d %f",  
				&(classifier->threshold), 
				&(classifier->parity), 
				&(classifier->alpha)); 
			 
			 
		}/* i */ 
	} 
 
	fclose(file); 
	file = NULL; 
	return TRUE; 
} 
 
 
ClassifierCascade* LoadClassifierCascade(const char* directory, int maxstep, MySize origWindowSize) 
{ 
	if(maxstep <= 0 || origWindowSize.width <= 0 || origWindowSize.height <= 0 ) 
	{ 
		return NULL; 
	} 
 
	ClassifierCascade* cascade = NULL; 
	if( directory && *directory ) 
	{ 
		cascade = new ClassifierCascade; 
		if( NULL == cascade ) 
			return NULL; 
 
		cascade->count = maxstep;        ///层数 
		cascade->origWindowSize.width = origWindowSize.width; 
		cascade->origWindowSize.height = origWindowSize.height; 
 
		cascade->stageClassifier = NULL; 
		cascade->stageClassifier = new StageClassifier[maxstep];//指向层分类器结构的数组 
		if( NULL == cascade->stageClassifier ) 
		{ 
			delete cascade; 
			cascade = NULL; 
			return NULL; 
		} 
		memset( cascade->stageClassifier, 0, sizeof(StageClassifier)*maxstep); 
 
		CString strFileName = _T(""); 
		CString suffix = _T(""); 
		for(int i = 1; i <=maxstep; i++) 
		{		 
			strFileName = directory; 
			strFileName += _T("\\stage"); 
			suffix.Format("%d.txt", i); 
			strFileName += suffix; 
 
			LoadStageClassifier( strFileName, &(cascade->stageClassifier[i-1]) ); 
		} 
	}//end for if 
 
	return cascade; 
	 
 
} 
 
 
 
DetCascadeClassifier* 
CreateDetCascadeClassifier( ClassifierCascade* cascade,  
						    int nImgWidth, int nImgHeight, 
						     
							double scale ) 
{ 
	assert( NULL != cascade ); 
 
	DetCascadeClassifier* out = NULL; 
	out = new DetCascadeClassifier; 
	assert(out != NULL); 
 
	out->count = cascade->count; 
	out->origWindowSize.width  = cascade->origWindowSize.width; 
	out->origWindowSize.height = cascade->origWindowSize.height; 
 
	out->stageClassifier = NULL; 
	out->stageClassifier = new DetStageClassifier[out->count]; 
	assert(NULL != out->stageClassifier); 
 
	int count = 0; 
	int i, j; 
	for(i = 0; i < cascade->count; i++) 
	{ 
		count = cascade->stageClassifier[i].count; 
		out->stageClassifier[i].count = count; 
		out->stageClassifier[i].threshold = cascade->stageClassifier[i].threshold; 
		out->stageClassifier[i].classifier = new DetHaarClassifier[count]; 
		assert(NULL != out->stageClassifier[i].classifier); 
 
		for(j = 0; j < count; j++) 
		{ 
			out->stageClassifier[i].classifier[j].alpha = cascade->stageClassifier[i].classifier[j].alpha; 
			out->stageClassifier[i].classifier[j].parity = cascade->stageClassifier[i].classifier[j].parity; 
			out->stageClassifier[i].classifier[j].threshold = cascade->stageClassifier[i].classifier[j].threshold; 
			CopyHaarFeature(cascade->stageClassifier[i].classifier[j].haarfeature, out->stageClassifier[i].classifier[j].origFeature); 
		} 
	}	 
 
 
 
	return out; 
 
} 
 
void SetImgForDetCascadeClassifier( DetCascadeClassifier* cascade, 
								    int* SAT, int* RSAT,double SSAT[], 
									int nImgWidth, int nImgHeight, 
									double scale ) 
{ 
	assert(NULL != cascade); 
	assert(NULL != SAT); 
	assert(NULL != SSAT); 
	assert(NULL!=RSAT); 
	assert(nImgWidth > 0 && nImgHeight > 0); 
	assert(scale >= 1.0F); 
 
	cascade->scale = scale; 
	cascade->realWindowSize.width = Round(cascade->origWindowSize.width * scale); 
	cascade->realWindowSize.height = Round(cascade->origWindowSize.height * scale); 
	cascade->imgSize.width = nImgWidth; 
	cascade->imgSize.height = nImgHeight; 
//	cascade->weight_scale=float(scale*scale); 
     double weight_scale; 
	weight_scale = 1/(scale * scale); 
	int step = cascade->imgSize.width; 
	MyRect equ_rect; 
	equ_rect.x = 0; 
	equ_rect.y = 0; 
	equ_rect.width = Round(cascade->origWindowSize.width * scale); 
	equ_rect.height = Round(cascade->origWindowSize.height * scale);	 
 
	cascade->invWindowArea = 1.0 / (equ_rect.width * equ_rect.height); 
 
	cascade->p0 = SAT+equ_rect.y*step+equ_rect.x; 
	cascade->p1 = SAT+equ_rect.y*step+equ_rect.x+equ_rect.width; 
	cascade->p2 = SAT+(equ_rect.y+equ_rect.height)*step+equ_rect.x; 
	cascade->p3 = SAT+(equ_rect.y+equ_rect.height)*step+equ_rect.x+equ_rect.width; //p0,p1,p2,p3组成一个SAT检测窗 
 
	cascade->ps0=SSAT+equ_rect.y*step+equ_rect.x; 
	cascade->ps1=SSAT+equ_rect.y*step+equ_rect.x+equ_rect.width; 
	cascade->ps2= SSAT+(equ_rect.y+equ_rect.height)*step+equ_rect.x; 
	cascade->ps3=SSAT+(equ_rect.y+equ_rect.height)*step+equ_rect.x+equ_rect.width; //ps0,ps1,ps2,ps3组成一个SSAT检测窗 
 
	int i, j, k; 
	for(i = 0; i < cascade->count; i++) //阶数 
	{ 
		for(j = 0; j < cascade->stageClassifier[i].count; j++) //每阶的强分类器数 
		{ 
			HaarFeature* origFeature =  
				&(cascade->stageClassifier[i].classifier[j].origFeature); 
		 
			DetHaarFeature* detFeature =  
				&(cascade->stageClassifier[i].classifier[j].feature); 
		 
			double sum0 = 0.0F, area0 = 0.0F; 
			MyRect tr; 
		if ((*origFeature).type<8) 
		{ 
		 
			 
			for(k = 0; k < HAAR_FEATURE_MAX; k++)  //每个强分类器的Haar 特征数 
			{ 
				if(origFeature->rect[k].r.width == 0) 
				{ 
					detFeature->rect[k].weight = NULL; 
					detFeature->rect[k].p0=NULL; 
					detFeature->rect[k].p1 = NULL; 
					detFeature->rect[k].p2 = NULL; 
					detFeature->rect[k].p3 = NULL; 
					break; 
				} 
				 
 
				tr.x = Round(origFeature->rect[k].r.x * scale); 
                tr.y = Round(origFeature->rect[k].r.y * scale); 
				tr.width = Round(origFeature->rect[k].r.width * scale); 
				 
				tr.height = Round(origFeature->rect[k].r.height * scale); 
 
 				detFeature->rect[k].p0 = SAT + tr.y * step + tr.x; 
				detFeature->rect[k].p1 = SAT + (tr.y -tr.height)* step + tr.x ; 
				detFeature->rect[k].p2 = SAT + tr.y * step + tr.x-tr.width; 
				detFeature->rect[k].p3 = SAT + (tr.y -tr.height) * step + tr.x -tr.width; 
                detFeature->rect[k].weight = (float)(origFeature->rect[k].weight * weight_scale); 
                   if(k == 0) 
					area0 = tr.width * tr.height; 
				else 
					sum0 += detFeature->rect[k].weight * tr.width * tr.height; 
			}/* k */ 
        }/*if*/ 
		else 
		{ 
				assert((*origFeature).type>7); 
			for(k = 0; k < HAAR_FEATURE_MAX; k++) 
			{ 
				if(origFeature->rect[k].r.width == 0) 
				{ 
					detFeature->rect[k].weight = NULL; 
					detFeature->rect[k].p1 = NULL; 
					detFeature->rect[k].p2 = NULL; 
					detFeature->rect[k].p3 = NULL; 
					break; 
				} 
 
				tr.x = Round(origFeature->rect[k].r.x * scale); 
				tr.width = Round(origFeature->rect[k].r.width * scale); 
				tr.y = Round(origFeature->rect[k].r.y * scale); 
				tr.height = Round(origFeature->rect[k].r.height * scale); 
 
				detFeature->rect[k].p0 = RSAT + tr.y * step + tr.x; 
				detFeature->rect[k].p1 = RSAT + (tr.y-tr.width) * step + tr.x + tr.width; 
				detFeature->rect[k].p2 = RSAT + (tr.y - tr.height) * step + tr.x- tr.height; 
				detFeature->rect[k].p3 = RSAT + (tr.y-tr.width-tr.height) * step + tr.x+ tr.width-tr.height; 
                detFeature->rect[k].weight = (float)(origFeature->rect[k].weight * weight_scale); 
			if(k == 0) 
					area0 = tr.width * tr.height; 
				else 
					sum0 += detFeature->rect[k].weight * tr.width * tr.height; 
			 
			} 
			 
		}/* if */ 
		detFeature->rect[0].weight = (float)(-sum0 / area0); 
	}/* j */ 
}/* i */ 
} 
 
int RunDetCascadeClassifier( DetCascadeClassifier* cascade,							  
							POS pt ) 
{ 
	assert( NULL != cascade ); 
 
	int sumImgWidth = cascade->imgSize.width; 
	int sumImgHeight = cascade->imgSize.height; 
	if( pt.x < 0 || pt.y < 0 || 
		pt.x + cascade->realWindowSize.width >= sumImgWidth - 2 || 
		pt.y + cascade->realWindowSize.height >= sumImgHeight - 2 ) 
	{ 
		return 0; 
	} 
 
	double mean, norm_factor; 
	int p_offset = pt.y * sumImgWidth + pt.x; 
	int pq_offset = pt.y * sumImgWidth + pt.x; 
	mean = (cascade->p0[p_offset] - cascade->p1[p_offset] - 
		    cascade->p2[p_offset] + cascade->p3[p_offset]) * cascade->invWindowArea; 
	norm_factor = cascade->ps0[pq_offset] - cascade->ps1[pq_offset] - 
		          cascade->ps2[pq_offset] + cascade->ps3[pq_offset]; 
	norm_factor =  
		sqrt(norm_factor*cascade->invWindowArea - mean*mean); 
//	if(norm_factor == 0.0 || mean == 0.0) 
	//	return -1; 
 
	float stage_sum = 0.0F; 
	int i, j; 
	for(i = 0; i < cascade->count; i++)  //阶数 
	{		 
		stage_sum = 0.0F; 
 
		for(j = 0; j < cascade->stageClassifier[i].count; j++)  //每阶的强分类器数 
		{ 
			DetHaarClassifier* classifier = cascade->stageClassifier[i].classifier + j; 
			DetHaarFeature* feature = &(classifier->feature); 
			double sum = 0.0F; 
			float thresh = classifier->threshold * norm_factor; 
 
			sum += (feature->rect[0].p0[p_offset] -  
				    feature->rect[0].p1[p_offset] - 
				    feature->rect[0].p2[p_offset] +  
					feature->rect[0].p3[p_offset])*  
   					feature->rect[0].weight; 
			     
			sum += (feature->rect[1].p0[p_offset] - 
				    feature->rect[1].p1[p_offset] - 
				    feature->rect[1].p2[p_offset] +  
					feature->rect[1].p3[p_offset])*  
					feature->rect[1].weight; 
 
			if(feature->rect[2].weight) 
				sum += (feature->rect[2].p0[p_offset] -  
				        feature->rect[2].p1[p_offset] -  
						feature->rect[2].p2[p_offset] +  
						feature->rect[2].p3[p_offset])*  
						feature->rect[2].weight; 
				          
           //  assert(sum==0); 
			if(0.5*sum * classifier->parity < thresh * classifier->parity ) 
				stage_sum += classifier->alpha; 
		 
		} 
 
		if(stage_sum < cascade->stageClassifier[i].threshold ) 
		{ 
			return -1; 
		} 
	}/* i */ 
 
	return 1; 
} 
 
int is_equal( const void* _r1, const void* _r2) 
{ 
	const MyRect* r1 = (const MyRect*)_r1; 
	const MyRect* r2 = (const MyRect*)_r2; 
 
    int distance = Round(r1->width*0.1); 
 
    if( r2->x <= r1->x + distance && 
        r2->x >= r1->x - distance && 
        r2->y <= r1->y + distance && 
        r2->y >= r1->y - distance && 
        r2->width <= Round( r1->width * 1.1 ) && 
        Round( r2->width * 1.1 ) >= r1->width ) 
	{ 
		return 1; 
	} 
 
	return 0; 
} 
 
typedef struct CvPTreeNode 
{ 
    struct CvPTreeNode* parent; 
    MyRect* element; 
    int rank; 
} 
CvPTreeNode; 
 
int RectsPartition(vector* vecFaces, vector* labels, ComFunc is_equal) 
{ 
	assert(vecFaces && labels); 
 
	int class_idx = 0; 
	vector *nodes = 0;  
	nodes = new vector; 
	nodes->clear();  //nodes 是容器指针,该容器里存放的是CvPTreeNode 
 
	int i, j; 
 
	// Initial O(N) pass. Make a forest of single-vertex trees. 
	for(i = 0; i < vecFaces->size(); i++) 
	{ 
		CvPTreeNode node = {0, 0, 0}; 
		node.element = &(vecFaces->at(i)); 
		nodes->push_back(node);//nodes 中存放的CvPTreeNode的element指向vecfaces中的RECT 
	} 
 
	 // The main O(N^2) pass. Merge connected components. 
	for(i = 0; i < nodes->size(); i++) 
	{ 
		CvPTreeNode* node1 = &nodes->at(i); 
		CvPTreeNode* root = node1; 
 
		while( root->parent ) 
            root = root->parent; 
 
		for(j = 0; j < nodes->size(); j++) 
		{ 
			CvPTreeNode* node2 = &nodes->at(j); 
 
			if( node2->element && node2 != node1 && 
                is_equal( node1->element, node2->element)) 
            { 
				CvPTreeNode* root2 = node2; 
                 
                // unite both trees 
                while( root2->parent ) 
                    root2 = root2->parent; 
 
				if( root2 != root ) 
                { 
                    if( root->rank > root2->rank ) 
                        root2->parent = root; 
                    else 
                    { 
                        root->parent = root2; 
                        root2->rank += root->rank == root2->rank; 
                        root = root2; 
                    } 
                    assert( root->parent == 0 ); 
 
                    // compress path from node2 to the root 
                    while( node2->parent ) 
                    { 
                        CvPTreeNode* temp = node2; 
                        node2 = node2->parent; 
                        temp->parent = root; 
                    } 
 
                    // compress path from node to the root 
                    node2 = node1; 
                    while( node2->parent ) 
                    { 
                        CvPTreeNode* temp = node2; 
                        node2 = node2->parent; 
                        temp->parent = root; 
                    } 
                } 
			} 
		}// end for j 
	}// end for i 
 
	labels->clear(); 
	for( i = 0; i < nodes->size(); i++ ) 
    { 
        CvPTreeNode* node = &nodes->at(i); 
        int idx = -1; 
         
        if( node->element ) 
        { 
            while( node->parent ) 
                node = node->parent; 
            if( node->rank >= 0 ) 
                node->rank = ~class_idx++; 
            idx = ~node->rank; 
        } 
		labels->push_back(idx); 
    } 
 
	nodes->clear(); 
	delete nodes; 
 
	return class_idx; 
} 
 
void HaarDetectFaces( BYTE* pbyteSrcImg,  
					  int iw, int ih, 
					  MyRect detRegion, 
					  DetCascadeClassifier* cascade, 
					  vector* vecFaces, 
					  MySize min_size, 
					  MySize max_size, 
					  int min_neighbors, 
					  double scale_factor )		 
{ 
	assert(pbyteSrcImg != NULL); 
	assert(NULL != cascade && NULL != vecFaces); 
	assert(detRegion.x >= 0 && detRegion.y >=0 &&  
		   detRegion.width <= iw && detRegion.height <= ih);		    
    assert(min_size.width > 0 && min_size.height > 0); 
    assert(max_size.width <= detRegion.width&& max_size.width <= detRegion.height);  
	assert(max_size.height <= detRegion.width&&max_size.height <= detRegion.height); 
		 
 
	cascade->imgSize.width = iw; 
	cascade->imgSize.height = ih; 
	int size = iw * ih; 
	int *SAT = NULL; 
	int *RSAT = NULL; 
	double *SSAT=NULL; 
	SAT = new int[size]; 
	RSAT = new int[size]; 
    SSAT=new double[size]; 
 
 
    IntegralImage(pbyteSrcImg, SAT,RSAT,SSAT, iw, ih);  // 
 
	 
	vector origFaces, tempFaces; 
	origFaces.clear(); 
	tempFaces.clear(); 
	vecFaces->clear(); 
 
	double factor = 1.0; 
	int iMaxSize = MIN(max_size.width, max_size.height); 
	for( factor = 1; factor*cascade->origWindowSize.width < iMaxSize; factor *= scale_factor ) //逐步扩大检测窗口 
	{ 
		const double ystep = MAX( 2, factor ); 
		MySize win_size = {Round(cascade->origWindowSize.width * factor),  
			              Round(cascade->origWindowSize.height * factor)}; 
		int stop_height = Round((detRegion.height - win_size.height) / ystep); 
 
		if(win_size.width < min_size.width || win_size.height < min_size.height) 
			continue; 
 
		SetImgForDetCascadeClassifier(cascade, SAT,RSAT,SSAT, iw, ih, factor);  // 
 
		for(int _iy = 1; _iy < stop_height; _iy++) 
		{ 
			int iy = detRegion.y + Round(_iy*ystep); 
			int _xstep = 1; 
			int stop_width = Round((detRegion.width - win_size.width) / ystep); 
			for(int _ix = 0; _ix < stop_width; _ix += _xstep) 
			{ 
				int ix = detRegion.x + Round(_ix*ystep); 
				POS pt; 
				pt.x = ix; 
				pt.y = iy;	            
				int result; 
			 
				result = RunDetCascadeClassifier(cascade, pt); 
				if(result > 0)        //如果RunDetCascadeClassifier函数判断出当前窗口为人脸 
				{ 
					MyRect rect;      //则记录其起点位置,和长宽。 
					rect.x = pt.x; 
					rect.y = pt.y; 
					rect.width = win_size.width; 
					rect.height = win_size.height; 
					origFaces.push_back(rect); 
				} 
			}/* ix */ 
		}/* iy */ 
	}/* factor */ 
 
	 
	//释放内存 
	delete[] SAT; 
	delete[] RSAT; 
	delete []SSAT; 
	SAT=NULL; 
	RSAT=NULL; 
	SSAT=NULL; 
 
if( min_neighbors != 0 ) 
	{ 
		// group retrieved rectangles 
		vector labels; 
clock_t start, finish; 
double  duration; 
start = clock(); 
		int nclasses = RectsPartition(&origFaces, &labels, is_equal); 
finish = clock(); 
duration = (double)(finish - start) / CLOCKS_PER_SEC; 
CString tmp; 
tmp.Format("qq%f",duration); 
AfxMessageBox(tmp); 
		 
		int* neighbors = new int[nclasses]; 
		MyRect *rects = new MyRect[nclasses]; 
		memset(neighbors, 0, nclasses*sizeof(neighbors[0])); 
		memset(rects, 0, nclasses*sizeof(rects[0]));		 
 
		// count number of neighbors 
		for(int i = 0; i < origFaces.size(); i++) 
		{ 
			MyRect r = origFaces.at(i); 
			int idx = labels.at(i); 
			 
			neighbors[idx]++; 
			rects[idx].x += r.x; 
			rects[idx].y += r.y; 
			rects[idx].width += r.width; 
			rects[idx].height += r.height; 
		} 
 
		// calculate average bounding box 
//		vector tempNeighbors; 
//		tempNeighbors.clear(); 
		for(i = 0; i < nclasses; i++) 
		{ 
			int n = neighbors[i]; 
			if( n >= min_neighbors ) 
			{ 
				MyRect rect; 
				rect.x = (rects[i].x*2 + n) / (2*n); 
				rect.y = (rects[i].y*2 + n) / (2*n); 
				rect.width = (rects[i].width*2 + n) / (2*n); 
				rect.height = (rects[i].height*2 + n) / (2*n); 
				tempFaces.push_back(rect); 
//				tempNeighbors.push_back(neighbors[i]); 
			} 
		} 
		delete[] neighbors; 
		delete[] rects; 
 
		// filter out small face rectangles inside large face rectangles 
		for(i = 0; i < tempFaces.size(); i++) 
		{ 
			MyRect r1 = tempFaces.at(i); 
//			int nb1 = tempNeighbors.at(i); 
			int flag = 1; 
 
//			printf("%d %d %d %d %d\n", r1.x, r1.y, r1.width, r1.height, nb1); 
 
			for(int j = 0; j < tempFaces.size(); j++) 
			{ 
				MyRect r2 = tempFaces.at(j); 
//				int nb2 = tempNeighbors.at(j); 
				int distance = Round(r2.width * 0.2); 
 
				if( (i != j) && 
					(r1.x >= r2.x) && 
					(r1.y >= r2.y) &&  
					(r1.x + r1.width <= r2.x + r2.width) && 
					(r1.y + r1.height <= r2.y + r2.height) )//&& 
//					(nb2 > MAX(3, nb1) || nb1 < 3 ) ) 
				{ 
					flag = 0; 
					break; 
				} 
			} 
 
			if( flag ) 
				vecFaces->push_back(r1); 
		} 
	} 
// 
 
// 
} 
 
void ReleaseDetCascadeClassifier(DetCascadeClassifier* cascade) 
{ 
	if( NULL == cascade ) 
		return; 
 
	for(int i = 0; i < cascade->count; i++) 
	{ 
		for(int j = 0; j < cascade->stageClassifier[i].count; j++) 
		{ 
			DetHaarClassifier* classifier = &(cascade->stageClassifier[i].classifier[j]); 
			for(int k = 0; k < HAAR_FEATURE_MAX; k++) 
			{ 
				classifier->feature.rect[k].p0 = NULL; 
				classifier->feature.rect[k].p1 = NULL; 
				classifier->feature.rect[k].p2 = NULL; 
				classifier->feature.rect[k].p3 = NULL; 
			} 
		} 
		delete[] cascade->stageClassifier[i].classifier; 
		cascade->stageClassifier[i].classifier = NULL;		 
	} 
 
	delete[] cascade->stageClassifier; 
	cascade->stageClassifier = NULL; 
 
	delete cascade; 
	cascade = NULL; 
} 
 
void ReleaseClassifierCascade(ClassifierCascade* cascade) 
{ 
	if( NULL == cascade ) 
		return; 
 
	for(int i = 0; i < cascade->count; i++) 
	{ 
		delete[] cascade->stageClassifier[i].classifier; 
		cascade->stageClassifier[i].classifier = NULL; 
	} 
	 
	delete[] cascade->stageClassifier; 
	cascade->stageClassifier = NULL; 
 
	delete cascade; 
	cascade = NULL; 
}