www.pudn.com > FacialFeature.rar > FacialFeatureDlg.cpp


// FacialFeatureDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "FacialFeature.h" 
#include "FacialFeatureDlg.h" 
#include "ReplaceDlg.h" 
#include "AddSampleDlg.h" 
 
////////////////////////////adaboost 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#define ORIG_WIN_SIZE  24 
static CvMemStorage* storage = 0; 
static CvHidHaarClassifierCascade* hid_cascade = 0; 
#define WINNAME  "Result" 
 
//////////////////////////// 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CAboutDlg dialog used for App About 
 
class CAboutDlg : public CDialog 
{ 
public: 
	CAboutDlg(); 
 
// Dialog Data 
	//{{AFX_DATA(CAboutDlg) 
	enum { IDD = IDD_ABOUTBOX }; 
	//}}AFX_DATA 
 
	// ClassWizard generated virtual function overrides 
	//{{AFX_VIRTUAL(CAboutDlg) 
	protected: 
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support 
	//}}AFX_VIRTUAL 
 
// Implementation 
protected: 
	//{{AFX_MSG(CAboutDlg) 
	//}}AFX_MSG 
	DECLARE_MESSAGE_MAP() 
}; 
 
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 
{ 
	//{{AFX_DATA_INIT(CAboutDlg) 
	//}}AFX_DATA_INIT 
} 
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CAboutDlg) 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
	//{{AFX_MSG_MAP(CAboutDlg) 
		// No message handlers 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFacialFeatureDlg dialog 
 
CFacialFeatureDlg::CFacialFeatureDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CFacialFeatureDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CFacialFeatureDlg) 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
} 
 
void CFacialFeatureDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CFacialFeatureDlg) 
	DDX_Control(pDX, IDC_BMPSHOW, m_sizeofarea); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CFacialFeatureDlg, CDialog) 
	//{{AFX_MSG_MAP(CFacialFeatureDlg) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDC_BTN_OPENFILE, OnBtnOpenfile) 
	ON_BN_CLICKED(IDC_FACE_DETECT, OnFaceDetect) 
	ON_BN_CLICKED(IDC_EYE_CENTER, OnEyeCenter) 
	ON_BN_CLICKED(IDC_MOUTH_CENTER, OnMouthCenter) 
	ON_BN_CLICKED(IDC_NOSE_CENTER, OnNoseCenter) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFacialFeatureDlg message handlers 
 
BOOL CFacialFeatureDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Add "About..." menu item to system menu. 
 
	// IDM_ABOUTBOX must be in the system command range. 
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
	ASSERT(IDM_ABOUTBOX < 0xF000); 
 
	CMenu* pSysMenu = GetSystemMenu(FALSE); 
	if (pSysMenu != NULL) 
	{ 
		CString strAboutMenu; 
		strAboutMenu.LoadString(IDS_ABOUTBOX); 
		if (!strAboutMenu.IsEmpty()) 
		{ 
			pSysMenu->AppendMenu(MF_SEPARATOR); 
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
		} 
	} 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
 
	// TODO: Add extra initialization here 
	//////////////////// by zzl 
	m_pMainDibBmp = new CDib(); 
	image   = NULL; 
	grayimg = NULL; 
	edgeimg = NULL; 
	yuvimg  = NULL; 
	m_nBmpWidth = 0; 
	m_nBmpHeigh = 0; 
	m_sBmpName = ""; 
	m_tPixelOfOriBmpArray = NULL; 
	m_tPixelOfRefBmpArray = NULL; 
	m_pRefMap = NULL; 
 
 
	CWnd *pWnd0 = GetDlgItem(IDC_BMPSHOW); 
	pDCShow = pWnd0->GetDC(); 
	m_bFaceOK = false; 
	m_bShowFace = false; 
 
	m_rFaceArea = CRect(0,0,0,0); 
	m_rAdaFaceArea = CRect(0,0,0,0); 
 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CFacialFeatureDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
	if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
	{ 
		CAboutDlg dlgAbout; 
		dlgAbout.DoModal(); 
	} 
	else 
	{ 
		CDialog::OnSysCommand(nID, lParam); 
	} 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CFacialFeatureDlg::OnPaint()  
{ 
/* 
	CWnd* pWnd = GetDlgItem(IDC_BMPSHOW); 
	CDC* pControlDC = pWnd->GetDC(); 
	pWnd->Invalidate(); 
	pWnd->UpdateWindow(); 
	pControlDC->SelectStockObject(BLACK_BRUSH); 
	pControlDC->Rectangle(0,0,100,100); 
*/ 
	 
 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
		if (m_tPixelOfRefBmpArray == NULL) return; 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CFacialFeatureDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
void CFacialFeatureDlg::OnBtnOpenfile()  
{ 
	// TODO: Add your control notification handler code here 
	CAddSampleDlg FileDlg(TRUE, "", NULL, 
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, 
		"Color Face Image(*.bmp)|*.bmp|所有文件(*.*)|*.*||", 
		AfxGetMainWnd()); 
	CString strFile; 
	if (FileDlg.DoModal() != IDOK) 
		return; 
	POSITION pos = FileDlg.GetStartPosition(); 
	strFile = FileDlg.GetNextPathName(pos); 
	m_pMainDibBmp->Open(strFile); 
	m_nBmpWidth = m_pMainDibBmp->GetWidth(); 
	m_nBmpHeigh = m_pMainDibBmp->GetHeight(); 
	m_sBmpName = strFile; 
	m_rFaceArea.left = 0; 
	m_rFaceArea.right = 0; 
	m_rFaceArea.top = 0; 
	m_rFaceArea.bottom = 0; 
	m_rAdaFaceArea = CRect(0,0,0,0); 
 
	m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK = 
	m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK =  
	m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false; 
 
	m_bMidMouthOK = m_bMidNoseOK = false; 
 
	m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner =  
	m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner = 
	m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1); 
 
	SetCursor(LoadCursor(NULL, IDC_WAIT)); 
	LoadPixelOfBmp(m_pMainDibBmp); 
	CreateBitMap(); 
	SetCursor(LoadCursor(NULL, IDC_ARROW)); 
	 
} 
 
void CFacialFeatureDlg::LoadPixelOfBmp(CDib *pDib) 
{ 
	BYTE *colorTable; 
	colorTable = (BYTE *)pDib->m_pDibBits; 
	int byteBitCount = pDib->GetBiBitCount()/8; 
 
	m_tPixelOfOriBmpArray = new RGBQUAD*[m_nBmpHeigh]; 
	m_tPixelOfRefBmpArray = new RGBQUAD*[m_nBmpHeigh]; 
 
	for (int i = 0; i=0 ; m--) 
	{ 
		for(int n = 0; nGetWindow()); 
	if (m_pRefMap != NULL) 
		delete m_pRefMap; 
	m_pRefMap = new CBitmap(); 
	m_pRefMap->CreateCompatibleBitmap(&ClientDC, m_nBmpWidth, m_nBmpHeigh); 
 
	CDC dc; 
	dc.CreateCompatibleDC(&ClientDC); 
	dc.SelectObject(m_pRefMap); 
	for (int i=0; iGetWindow()->GetClientRect(&rc); 
	pDCShow->Rectangle(&rc); 
	CDC dc; 
	CBitmap *pOldBitmap; 
	dc.CreateCompatibleDC(pDCShow); 
	pOldBitmap = dc.SelectObject(m_pRefMap); 
	pDCShow->StretchBlt(0,0,m_nBmpWidth,m_nBmpHeigh,&dc,0,0,m_nBmpWidth,m_nBmpHeigh,SRCCOPY); 
	dc.SelectObject(pOldBitmap); 
	dc.DeleteDC(); 
 
} 
 
 
bool CFacialFeatureDlg::CopyBitMap(RGBQUAD **dest, RGBQUAD **source) 
{ 
	if(source==NULL || dest==NULL)  
		return false; 
	for(int i=0; iSelectObject(&pen); 
	pDC->MoveTo(point.x-7,point.y); 
	pDC->LineTo(point.x+7,point.y); 
	pDC->MoveTo(point.x,point.y-7); 
	pDC->LineTo(point.x,point.y+7); 
	pDC->SelectObject(oldPen); 
	pen.DeleteObject(); 
} 
 
 
 
void CFacialFeatureDlg::OnFaceDetect()  
{ 
	// TODO: Add your control notification handler code here 
	LightCompensation(); 
	ConverFromDib(); 
	 
	CvCapture* capture = 0; 
	CvHaarClassifierCascade* cascade = 
			cvLoadHaarClassifierCascade("", 
			cvSize(ORIG_WIN_SIZE, ORIG_WIN_SIZE)); 
	hid_cascade = cvCreateHidHaarClassifierCascade(cascade, 0, 0, 0, 1); 
	cvReleaseHaarClassifierCascade(&cascade); 
 
	storage = cvCreateMemStorage(0); 
 
//	IplImage* image = pDoc->m_Image->GetImage(); 
	 
	IplImage* temp = cvCreateImage(cvSize(image->width/2,image->height/2), 8, 3); 
	if(image) 
	{ 
		cvFlip(image, image, 0); 
		image->origin = IPL_ORIGIN_BL; 
 
		int scale = 2; 
		CvPoint pt1, pt2; 
	 
		cvPyrDown(image, temp, CV_GAUSSIAN_5x5 ); 
#ifdef WIN32 
		cvFlip(temp, temp, 0 ); 
#endif     
		cvClearMemStorage(storage); 
		if(hid_cascade) 
		{ 
			CvSeq* faces = cvHaarDetectObjects( temp, hid_cascade, storage, 
				1.2, 2, CV_HAAR_DO_CANNY_PRUNING ); 
			for(int i = 0; i < (faces ? faces->total : 0); i++ ) 
			{ 
				CvRect* r = (CvRect*)cvGetSeqElem( faces, i, 0 ); 
				pt1.x = r->x * scale; 
				pt2.x = (r->x+r->width) * scale; 
#ifdef WIN32             
				pt1.y = image->height - r->y * scale; 
				pt2.y = image->height - (r->y+r->height) * scale; 
#else 
				pt1.y = r->y*scale; 
				pt2.y = (r->y+r->height) * scale; 
#endif             
				 
 
////////////////////////////////////////////////////////////////////////// 
				// Display the faces in the image 
				{ 
					CvRect region;  
					region.x = pt1.x; 
					region.y = r->y*scale; 
					region.width = r->width * scale; 
					region.height = r->height * scale; 
 
					///zzl 
					m_rFaceArea.top = pt1.y; 
					m_rFaceArea.bottom = pt2.y; 
					m_rFaceArea.left = pt1.x; 
					m_rFaceArea.right = pt2.x; 
					 
			 
					cvFlip(image, image, 0); 
					image->origin = IPL_ORIGIN_TL; 
					cvSetImageROI(image, region); 
 
					IplImage* image1 = cvCreateImage(cvSize(r->width*scale, 
						r->height*scale), image->depth, image->nChannels); 
 
					cvCopy(image, image1); 
 
					cvResetImageROI(image); 
//					cvNamedWindow("face", 1);  
				 
//					cvShowImage("face", image1); 
					cvWaitKey(0); 
					cvDestroyWindow("face"); 
					cvReleaseImage(&image1); 
					 
//					Invalidate(); 
 
					cvFlip(image, image, 0); 
					image->origin = IPL_ORIGIN_BL; 
					 
				} 
				 
////////////////////////////////////////////////////////////////////////// 
 
//				cvRectangle( image, pt1, pt2, CV_RGB(255,255,0), 3 ); 
 
			} 
		 
		} 
		 
        cvReleaseImage( &temp ); 
 
	int top,bottom,left,right,nFaceWidth; 
	nFaceWidth = m_rFaceArea.right - m_rFaceArea.left; 
	top = m_nBmpHeigh - m_rFaceArea.top; 
	bottom = m_nBmpHeigh - m_rFaceArea.bottom; 
	left = m_rFaceArea.left + nFaceWidth/8; 
	right = m_rFaceArea.right - nFaceWidth/8; 
	m_rAdaFaceArea = CRect(left-nFaceWidth/8,top,right+nFaceWidth/8,bottom); 
 
 
/* 
	for (int i=top; i<=bottom; i++) 
	{ 
		m_tPixelOfRefBmpArray[i][left].rgbBlue = 0; 
		m_tPixelOfRefBmpArray[i][left].rgbGreen = 0; 
		m_tPixelOfRefBmpArray[i][left].rgbRed = 0; 
		m_tPixelOfRefBmpArray[i][right].rgbBlue = 0; 
		m_tPixelOfRefBmpArray[i][right].rgbGreen = 0; 
		m_tPixelOfRefBmpArray[i][right].rgbRed = 0; 
		m_tPixelOfRefBmpArray[i][(int)((m_rFaceArea.left +m_rFaceArea.right)/2)].rgbBlue = 0; 
	} 
*/ 
	 
/*	for (j=left; j<=right; j++) 
	{ 
		m_tPixelOfRefBmpArray[top - 5][j].rgbBlue = 0; 
		m_tPixelOfRefBmpArray[top - 5][j].rgbGreen = 0; 
		m_tPixelOfRefBmpArray[top - 5][j].rgbRed = 0; 
		m_tPixelOfRefBmpArray[bottom][j].rgbBlue = 0; 
		m_tPixelOfRefBmpArray[bottom][j].rgbGreen = 0; 
		m_tPixelOfRefBmpArray[bottom][j].rgbRed = 0; 
//		m_tPixelOfRefBmpArray[(int)(2*(m_rFaceArea.bottom - m_rFaceArea.top)/3) + m_rFaceArea.top][j].rgbRed = 0; 
//		m_tPixelOfRefBmpArray[(int)((m_rFaceArea.bottom - m_rFaceArea.top)/3) + m_rFaceArea.top][j].rgbGreen = 0; 
 
	} 
*/ 
	//重新调整脸部区域的参数,方便进行特征的检测与定位 
 
 
	CRect rect(left,top,right,bottom); 
	m_rFaceArea = rect; 
	m_bFaceOK = true; 
	m_bShowFace = true; 
 
	CreateBitMap(); 
	} 
	 
//	Invalidate(); 
 
} 
 
void CFacialFeatureDlg::ConverFromDib() 
{ 
	CvSize ImgSize; 
	ImgSize.width = m_nBmpWidth; 
	ImgSize.height = m_nBmpHeigh; 
	image = cvCreateImage(ImgSize, IPL_DEPTH_8U, 3); 
	 
	BYTE* IplImg = (BYTE*)(image->imageData); 
	for(int i = 0; i < m_nBmpHeigh; i++) 
	for(int j = 0; j < m_nBmpWidth; j++) 
	{ 
		IplImg[3*(j + i*m_nBmpWidth)]     = m_tPixelOfRefBmpArray[i][j].rgbBlue; 
		IplImg[3*(j + i*m_nBmpWidth) + 1] = m_tPixelOfRefBmpArray[i][j].rgbGreen; 
		IplImg[3*(j + i*m_nBmpWidth) + 2] = m_tPixelOfRefBmpArray[i][j].rgbRed; 
 
	} 
 
} 
 
void CFacialFeatureDlg::OnEyeCenter()  
{ 
	// TODO: Add your control notification handler code here 
	if (!(m_bFaceOK && m_bShowFace)) { 
		AfxMessageBox("Please detect face first!"); 
		return; 
	} 
	int top,bottom,left,right,nFaceWidth; 
	nFaceWidth = m_rFaceArea.right - m_rFaceArea.left; 
	top = m_nBmpHeigh - m_rFaceArea.top; 
	bottom = m_nBmpHeigh - m_rFaceArea.bottom; 
	left = m_rFaceArea.left + nFaceWidth/8; 
	right = m_rFaceArea.right - nFaceWidth/8; 
 
	CPoint LeftEyeArea(-1,-1), RightEyeAre(-1,-1); 
	//人脸区域参数的进一步细化 
	int nLeft,nRight,nTop,nBottom; 
	nLeft = m_rFaceArea.left + 2; 
	nRight = m_rFaceArea.right - 2; 
	nBottom = m_rFaceArea.bottom -2; 
	nTop = m_rFaceArea.top + 2; 
	//眼睛参数的大致估计:三庭五眼 
	int nEyeWidth = 0.28*(nRight - nLeft);//0.28是一个经验数值,可以修改 
	int nEyeHeigh = nEyeWidth/3; 
	int nFaceCerH = (m_rFaceArea.right + m_rFaceArea.left)/2; 
	int nFaceCerV = (m_rFaceArea.bottom + m_rFaceArea.top)/2; 
	SetPixelValArray(m_tPixelOfRefBmpArray, 0); 
	//将人脸区域转换为灰度 
	for(int i=nTop; iwidth,image->height), IPL_DEPTH_8U,1); 
	edgeimg = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1); 
	cvCvtColor(image,grayimg,CV_BGR2GRAY); 
	cvCanny(grayimg,edgeimg,0,128,3);//0,128是经验值,程序死掉的地方之一 
	cvFlip(edgeimg,edgeimg,0); 
	BYTE* IplEdge = (BYTE*)edgeimg->imageData; 
	SetPixelValArray(m_tPixelOfRefBmpArray,0); 
	float zzl = 0; 
	for(i=0; iLeftEyeArea.x-nEyeWidth/2; i--) 
	for(i=LeftEyeArea.x+1.1*nEyeHeigh; i>LeftEyeArea.x+nEyeHeigh/2; i--) 
	{ 
		for(int j=LeftEyeArea.y+nEyeWidth/4; j>LeftEyeArea.y; j--) 
		{ 
			if (m_tPixelOfRefBmpArray[j][i].rgbBlue == 255)  
			{	 
				findcornerLr = true; 
				m_LeftEyeRightCorner.x=i; 
				m_LeftEyeRightCorner.y=j; 
				break; 
			} 
		} 
		if (findcornerLr) {m_bLeftEyeRightCornerOK = TRUE; break;} 
	} 
	 
	//左眼左眼角 
	bool findcornerLl = false; 
//	for(i=LeftEyeArea.x-nEyeWidth/2+5; iLeftEyeArea.y-nEyeWidth/4; j--) 
		{ 
			if (m_tPixelOfRefBmpArray[j][i].rgbBlue == 255)  
			{	 
				findcornerLl = true; 
				m_LeftEyeLeftCorner.x=i; 
				m_LeftEyeLeftCorner.y=j+2;//2是一个经验值 
				break; 
			} 
		} 
		if (findcornerLl) {m_bLeftEyeLeftCornerOK = TRUE; break;} 
	} 
	 
	//右眼左眼角 
	bool findcornerRl = false; 
//	for(i=RightEyeAre.x-nEyeWidth/2+2; iRightEyeAre.y; j--) 
		{ 
			if (m_tPixelOfRefBmpArray[j][i].rgbBlue == 255)  
			{	 
				findcornerRl = true; 
				m_RightEyeLeftCorner.x=i; 
				m_RightEyeLeftCorner.y=j; 
				break; 
			} 
		} 
		if (findcornerRl) {m_bRightEyeLeftCornerOK = TRUE; break;} 
	} 
	 
	//右眼右眼角 
	bool findcornerRr = false; 
//	for(i=RightEyeAre.x+nEyeWidth/2-2; i>RightEyeAre.x-nEyeWidth/2; i--) 
	for(i=RightEyeAre.x+1.1*nEyeHeigh; i>RightEyeAre.x-nEyeHeigh/2; i--) 
	{ 
		for(int j=RightEyeAre.y; j>RightEyeAre.y-nEyeWidth/4; j--) 
		{ 
			if (m_tPixelOfRefBmpArray[j][i].rgbBlue == 255)  
			{	 
				findcornerRr = true; 
				m_RightEyeRightCorner.x=i; 
				m_RightEyeRightCorner.y=j+2; 
				break; 
			} 
		} 
		if (findcornerRr) {m_bRightEyeRightCornerOK = TRUE; break;} 
	} 
	 
	m_LeftEye = LeftEyeArea; 
	m_RightEye = RightEyeAre; 
	m_bLeftEyeOK = TRUE; 
	m_bRightEyeOK = TRUE; 
	CopyBitMap(m_tPixelOfRefBmpArray,m_tPixelOfOriBmpArray); 
	CreateBitMap(); 
} 
 
void CFacialFeatureDlg::OnMouthCenter()  
{ 
	// 嘴巴特征的鉴别:1、色度空间;2、边缘信息 
	if (!m_bLeftEyeOK) 
	{ 
		AfxMessageBox("Please detect eyes first!"); 
		return; 
	} 
	//眼睛的倾斜角度 
/* 
	double tanEye; 
	if (m_RightEye.y == m_LeftEye.y) tanEye = 0; 
	else tanEye = double((m_RightEye.y - m_LeftEye.y))/(m_RightEye.x - m_LeftEye.x); 
*/ 
	//双眼的距离 
	int EyesDis = (m_RightEye.x - m_LeftEye.x)*(m_RightEye.x - m_LeftEye.x); 
	EyesDis += (m_RightEye.y - m_LeftEye.y)*(m_RightEye.y - m_LeftEye.y); 
	EyesDis = (int)sqrt(EyesDis); 
	//可能的嘴巴水平区域在脸的下部1/4处,竖直区域在双眼之间 
	int MouthUp    = m_rFaceArea.bottom - (m_rFaceArea.bottom - m_rFaceArea.top)/4; 
	int MouthDown  = m_rFaceArea.bottom; 
	int MouthLeft  = m_LeftEye.x; 
    int MouthRight = m_RightEye.x; 
	//嘴巴区域的颜色空间 
	SetPixelValArray(m_tPixelOfRefBmpArray,0); 
	yuvimg = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1); 
	IplImage* temp = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U,1);; 
	cvFlip(yuvimg,yuvimg,0); 
	 
	BYTE* IplYuv = (BYTE*)yuvimg->imageData; 
	BYTE* IplTemp = (BYTE*)temp->imageData; 
 
	double nThreshold = 0.25; 
	bool mouthCornerOK = true; 
	bool mouthR = false; 
	bool mouthL = false; 
 
	BYTE R,G,B; 
	double tempcolor,delta; 
 
 
	while (mouthCornerOK)  
	{ 
		for(int i=MouthUp; iMouthUp; i--) 
			{ 
				if (m_tPixelOfRefBmpArray[i][j].rgbRed == 255)  
				{ 
					m_LeftMouthCorner.x = j; 
					m_LeftMouthCorner.y = i; 
					mouthL = true; 
					break; 
				} 
			} 
			if (mouthL) break; 
		} 
		//right corner 
		for(j=MouthRight; j>MouthLeft; j--) 
		{ 
			for(i=MouthDown; i>MouthUp; i--) 
			{ 
				if (m_tPixelOfRefBmpArray[i][j].rgbRed == 255) 
				{ 
					m_RightMouthCorner.x = j; 
					m_RightMouthCorner.y = i; 
					mouthR = true; 
					break; 
				} 
			} 
			if (mouthR) break; 
		} 
		//适应不同光照下的阈值调节 
		if (nThreshold>=0.2 && nThreshold<=0.5 && (m_RightMouthCorner.x - m_LeftMouthCorner.x)<(m_RightEye.x - m_LeftEye.x)*0.5) 
		{ 
			nThreshold += 0.05; 
			mouthR = false; 
			mouthL = false; 
		} 
		else if (nThreshold>0 && nThreshold<=0.2 && (m_RightMouthCorner.x - m_LeftMouthCorner.x)>0.8*(m_RightEye.x - m_LeftEye.x)) 
		{ 
			nThreshold -= 0.05; 
			mouthR = false; 
			mouthL = false; 
		} 
		else mouthCornerOK = false; 
	} 
 
	if (mouthR && mouthL )  
	{ 
		m_MidMouth.x = (m_LeftMouthCorner.x + m_RightMouthCorner.x)/2; 
		m_MidMouth.y = (m_LeftMouthCorner.y + m_RightMouthCorner.y)/2; 
		m_bLeftMouthCornerOK = TRUE; 
		m_bRightMouthCornerOK = TRUE; 
		//m_bMidMouthOK = TRUE; 
	} 
	else 
	{ 
		AfxMessageBox("can't detect mouth features!"); 
		return; 
	} 
	//修正数值4 
	m_LeftMouthCorner.y  -= 4; 
	m_LeftMouthCorner.x  -= 4; 
	m_RightMouthCorner.y -= 4; 
	m_RightMouthCorner.x += 4; 
 
	CopyBitMap(m_tPixelOfRefBmpArray,m_tPixelOfOriBmpArray); 
	CreateBitMap(); 
	cvReleaseImage(&yuvimg); 
	cvReleaseImage(&temp); 
 
} 
 
void CFacialFeatureDlg::OnNoseCenter()  
{ 
	if (!m_bLeftEyeOK) 
	{ 
		AfxMessageBox("Please detect eyes first!"); 
		return; 
	} 
	//眼睛,嘴巴和鼻孔的倾斜角度 
	double tanEye,tanMouth,tanNose; 
	if (m_RightEye.y == m_LeftEye.y) tanEye = 0; 
	else tanEye = double((m_RightEye.y - m_LeftEye.y))/(m_RightEye.x - m_LeftEye.x); 
	if (m_RightMouthCorner.y == m_LeftMouthCorner.y) tanMouth = 0; 
	else tanMouth = double((m_RightMouthCorner.y - m_LeftMouthCorner.y))/(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
 
	// 确定鼻子的水平区域在1/2和1/3之间, 竖直在两眼之间 
	int NoseUp    = (m_rFaceArea.bottom + m_rFaceArea.top)/2 + m_nBmpWidth/30; 
	int NoseDown  = m_rFaceArea.bottom - (m_rFaceArea.bottom - m_rFaceArea.top)/3+ m_nBmpWidth/30; 
	int NoseLeft  = m_LeftMouthCorner.x; 
	int NoseRight = m_RightMouthCorner.x; 
	//鼻子区域的gray空间 
	SetPixelValArray(m_tPixelOfRefBmpArray,0); 
	double threshold = 100; 
	double Y; 
	bool findnose = false; 
	 
	while (!findnose) 
	{ 
		for(int i=NoseUp; iNoseUp; i--) 
			{ 
				if (m_tPixelOfRefBmpArray[i][j].rgbRed == 255) 
				{ 
					m_LeftNostril.x = j; 
					m_LeftNostril.y = i; 
					noseL = true; 
					break; 
				} 
			} 
			if (noseL) break; 
		} 
		// right nostrill 
		bool noseR = false; 
		for(j=NoseRight; j>(m_LeftMouthCorner.x + m_RightMouthCorner.x)/2; j--) 
		{ 
			for(i=NoseDown; i>NoseUp; i--) 
			{ 
				if (m_tPixelOfRefBmpArray[i][j].rgbRed == 255) 
				{ 
					m_RightNostril.x = j; 
					m_RightNostril.y = i; 
					noseR = true; 
					break; 
				} 
			} 
			if(noseR) break; 
		} 
		//only find left nostrill 
		if (noseL && !noseR) 
		{ 
			m_RightNostril.y = m_LeftNostril.y; 
			m_RightNostril.x = m_LeftNostril.x + 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
			noseR = true; 
			findnose = true; 
		} 
		//only find right nostrill 
		if (noseR && !noseL)  
		{ 
			m_LeftNostril.y = m_RightNostril.y; 
			m_LeftNostril.x = m_RightNostril.x - 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
			noseL = true; 
			findnose = true; 
		} 
		//both are not found 
		if (!noseR && !noseL) 
		{ 
			threshold += 20;//调整阈值 
//			AfxMessageBox("cannt find nose feature, please try the other method!"); 
//			return; 
		} 
		if (noseL && noseR) 
		{ 
			if (m_RightNostril.y == m_LeftNostril.y) tanNose = 0; 
			else tanNose = double((m_RightNostril.y - m_LeftNostril.y))/(m_RightNostril.x - m_LeftNostril.x); 
			//修正鼻孔定的过于倾斜 
			if (fabs(tanNose - tanEye)>=0.1) 
			{ 
				if (double(m_LeftMouthCorner.y - m_LeftNostril.y)/(m_LeftMouthCorner.y-m_LeftEye.y)<0.2 
					|| double(m_LeftNostril.y-m_LeftEye.y)/(m_LeftMouthCorner.y-m_LeftEye.y)<0.3) 
				{ 
					m_LeftNostril.y = m_RightNostril.y; 
					m_LeftNostril.x = m_RightNostril.x - 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
				} 
				else if (double(m_RightMouthCorner.y - m_RightNostril.y)/(m_RightMouthCorner.y-m_RightEye.y)<0.2 
					|| double(m_RightNostril.y-m_RightEye.y)/(m_RightMouthCorner.y-m_RightEye.y)<0.3) 
				{ 
					m_RightNostril.y = m_LeftNostril.y; 
					m_RightNostril.x = m_LeftNostril.x + 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
				} 
				else if ((m_RightMouthCorner.y - m_RightNostril.y)<(m_LeftMouthCorner.y - m_LeftNostril.y)) 
				{ 
					m_LeftNostril.y = m_RightNostril.y; 
					m_LeftNostril.x = m_RightNostril.x - 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
				} 
				else if ((m_RightMouthCorner.y - m_RightNostril.y)<(m_LeftMouthCorner.y - m_LeftNostril.y)) 
				{ 
					m_LeftNostril.y = m_RightNostril.y; 
					m_LeftNostril.x = m_RightNostril.x - 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
				} 
			} 
 
			m_bLeftNostrilOK = TRUE; 
			m_bRightNostrilOK = TRUE; 
			findnose = true; 
		} 
	} 
	//一般而言,鼻孔的位置会定在外边缘,向里可能5象素调整 
	double sumL1 = 0, sumR1 = 0, sumL2 = 0, sumR2 = 0; 
	for(int i=-3; i<=3; i++) 
	{ 
		for(int j=-3; j<=3;j++) 
		{ 
			sumL1 += m_tPixelOfRefBmpArray[m_LeftNostril.y+i][m_LeftNostril.x+j].rgbBlue; 
			sumL2 += m_tPixelOfRefBmpArray[m_RightNostril.y+i][m_RightNostril.x+j].rgbBlue; 
			sumR1 += m_tPixelOfRefBmpArray[m_LeftNostril.y+i][m_LeftNostril.x + 5 + j].rgbBlue; 
			sumR2 += m_tPixelOfRefBmpArray[m_RightNostril.y+i][m_RightNostril.x + 5 + j].rgbBlue; 
		} 
	} 
	if (sumL2(m_LeftNostril.x-(m_RightNostril.x-m_LeftNostril.x)/2)) 
			m_LeftNostril.x = m_RightNostril.x - 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
		else 
			m_RightNostril.x = m_LeftNostril.x + 0.6*(m_RightMouthCorner.x - m_LeftMouthCorner.x); 
	} 
	//对于基本正面的图像,鼻孔的距离眼睛的高度大于距离嘴巴的高度 
	//一下属于强制措施,可以考虑改进 
	if ((double(m_LeftMouthCorner.y - m_LeftNostril.y)/(m_LeftMouthCorner.y-m_LeftEye.y)<0.2) 
		&& (double(m_RightMouthCorner.y - m_RightNostril.y)/(m_RightMouthCorner.y-m_RightEye.y)<0.2)) 
	{ 
		m_LeftNostril.x  = m_LeftMouthCorner.x + 0.2*(m_RightNostril.x - m_LeftNostril.x); 
		m_LeftNostril.y  = m_LeftMouthCorner.y - (m_LeftMouthCorner.y - m_LeftEye.y)/3; 
		m_RightNostril.x = m_RightNostril.x - 0.2*(m_RightNostril.x - m_LeftNostril.x); 
		m_RightNostril.y = m_LeftNostril.y; 
	} 
	if ((m_LeftMouthCorner.y - m_LeftNostril.y)>(m_LeftNostril.y-m_LeftEye.y) 
		&& (m_RightMouthCorner.y - m_RightNostril.y)>(m_RightNostril.y-m_RightEye.y))  
	{ 
		m_LeftNostril.x  = m_LeftMouthCorner.x + 0.2*(m_RightNostril.x - m_LeftNostril.x); 
		m_LeftNostril.y  = m_LeftMouthCorner.y - (m_LeftMouthCorner.y - m_LeftEye.y)/3; 
		m_RightNostril.x = m_RightNostril.x - 0.2*(m_RightNostril.x - m_LeftNostril.x); 
		m_RightNostril.y = m_LeftNostril.y; 
	} 
	CopyBitMap(m_tPixelOfRefBmpArray,m_tPixelOfOriBmpArray); 
	CreateBitMap(); 
	cvReleaseImage(&image); 
	cvReleaseImage(&grayimg); 
	cvReleaseImage(&edgeimg); 
	 
} 
 
void CFacialFeatureDlg::LightCompensation() 
{ 
	//对图像进行亮度gamma校正 
	int sumWhitePixel = 0; 
	 
}