www.pudn.com > FaceDetect.rar > FaceDetectDlg.cpp


// FaceDetectDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "FaceDetect.h" 
#include "FaceDetectDlg.h" 
#include "ReplaceDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#include "AddSampleDlg.h" 
 
///////////////////////////////////////////////////////////////////////////// 
// 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() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFaceDetectDlg dialog 
 
CFaceDetectDlg::CFaceDetectDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CFaceDetectDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CFaceDetectDlg) 
		// NOTE: the ClassWizard will add member initialization here 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
} 
 
void CFaceDetectDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CFaceDetectDlg) 
		// NOTE: the ClassWizard will add DDX and DDV calls here 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CFaceDetectDlg, CDialog) 
	//{{AFX_MSG_MAP(CFaceDetectDlg) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDC_BTN_BINARY, OnBtnBinary) 
	ON_BN_CLICKED(IDC_BTN_EDGE, OnBtnEdge) 
	ON_BN_CLICKED(IDC_BTN_FACEHAIR, OnBtnFacehair) 
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_FACE, OnBtnHistogramFace) 
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_H, OnBtnHistogramH) 
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_HAIR, OnBtnHistogramHair) 
	ON_BN_CLICKED(IDC_BTN_HISTOGRAM_V, OnBtnHistogramV) 
	ON_BN_CLICKED(IDC_BTN_LIKEHOOD, OnBtnLikehood) 
	ON_BN_CLICKED(IDC_BTN_MARK_EYE, OnBtnMarkEye) 
	ON_BN_CLICKED(IDC_BTN_MARK_FACE_1, OnBtnMarkFace1) 
	ON_BN_CLICKED(IDC_BTN_MARK_FACE_2, OnBtnMarkFace2) 
	ON_BN_CLICKED(IDC_BTN_MARK_MOUSE, OnBtnMarkMouse) 
	ON_BN_CLICKED(IDC_BTN_MARK_NOSE, OnBtnMarkNose) 
	ON_BN_CLICKED(IDC_BTN_OPENFILE, OnBtnOpenfile) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFaceDetectDlg message handlers 
 
BOOL CFaceDetectDlg::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 
	CWnd *pWnd0= GetDlgItem(IDC_BMPSHOW); 
	pDCShow = pWnd0->GetDC(); 
 
	m_pMainDib = new CDib(); 
 
	m_tOriPixelArray = NULL; 
	m_tResPixelArray = NULL; 
 
	m_pResMap = NULL; 
 
	m_nWndWidth = 0; 
	m_nWndHeight= 0; 
	m_sFileName = ""; 
 
	m_bSelectByMan = false; 
	m_bLBottonDown = false; 
 
	m_ManLeft = -1; 
	m_ManRight = -1; 
	m_ManTop = -1; 
	m_ManBottom = -1; 
 
	m_bFaceOK = false; 
	m_bShowFace = false; 
	m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0; 
 
	m_bManualMarkFacial = false; 
	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); 
	 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CFaceDetectDlg::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 CFaceDetectDlg::OnPaint()  
{ 
	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_tResPixelArray==NULL) return; 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CFaceDetectDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 画十字形标记 
// 参数:  pDC-CDC指针 
//         point-要画的点的坐标 
//         crColor-标记得颜色 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::DrawCross(CDC *pDC, CPoint point, COLORREF crColor) 
{ 
	CPen pen,*oldPen; 
	pen.CreatePen(PS_SOLID,1,crColor); 
	oldPen = (CPen*)pDC->SelectObject(&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(); 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 拷贝位图 
// 参数:  dest-目标位图指针 
//         source-源位图指针 
//////////////////////////////////////////////////////////////////////////////// 
bool CFaceDetectDlg::CopyBitMap(RGBQUAD **dest, RGBQUAD **source) 
{ 
	if(source==NULL || dest==NULL)  
		return false; 
	for(int i=0; iGetWindow()); 
	if(m_pResMap!=NULL) delete m_pResMap; 
 
	m_pResMap=new CBitmap(); 
	m_pResMap->CreateCompatibleBitmap(&ClientDC,m_nWndWidth,m_nWndHeight); 
 
	CDC  dc; 
	dc.CreateCompatibleDC(&ClientDC); 
	dc.SelectObject(m_pResMap); 
 
	for(int i=0; im_pDibBits; 
	int byteBitCount  = pDib->GetBiBitCount()/8; 
 
	m_tOriPixelArray  = new RGBQUAD*[m_nWndHeight]; 
	m_tResPixelArray  = new RGBQUAD*[m_nWndHeight]; 
	for(int l=0 ; l=0; i--) 
	{ 
		for(int j=0; j 0.246 && r<0.664 && r>0.233 && r>g && g>=0.5*(1-r)) 
		{ 
			target[i][j].rgbRed = 255;  //face 
		} 
		else target[i][j].rgbRed = 0; 
	} 
	 
	for(i=top+2; i=5)positive++; 
		} 
		if(positive>2 && negtive>2)  
		{ 
			target[i][j].rgbBlue = target[i][j].rgbGreen = target[i][j].rgbRed = 0; 
		} 
 
	} 
 
	if(result!=NULL) 
	{ 
		for (int i=0 ;iCalBinary()) 
	{ 
		AfxMessageBox("请先计算相似度!"); 
		SetCursor(LoadCursor(NULL,IDC_ARROW));	 
		return; 
	} 
	 
	m_bShowFace = false; 
	for(int i=0; im_pBinaryArray[i][j]*255); 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));	 
	MyDraw(); 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 边缘提取 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnEdge()  
{ 
	if(!m_bFaceOK) 
	{ 
		AfxMessageBox("请先确定脸部区域"); 
		return; 
	} 
	//左右眼的水平区域 
	int nLeft,nRight,nTop,nBottom; 
 
	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0; 
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; 
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0; 
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; 
	//边缘检查 
	DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray); 
	MakeBitMap();	 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 求取头发和脸部区域 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnFacehair()  
{ 
	m_bShowFace = false; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	method2->MarkHairFace(); 
	for(int i=0; im_pBinaryArray[i][j]) 
		{ 
		case 0: 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	0; 
			m_tResPixelArray[i][j].rgbRed  = 255; 
			break; 
		case 1: 
			m_tResPixelArray[i][j].rgbBlue = 255; 
			m_tResPixelArray[i][j].rgbGreen=m_tResPixelArray[i][j].rgbRed=0; 
			break; 
		case 2: 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 0; 
			break; 
		} 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));	 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 脸部区域直方图 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnHistogramFace()  
{ 
	if(!method2->m_bBinaryOK) 
	{ 
		AfxMessageBox("请先计算二值化图!"); 
		return; 
	} 
 
	m_bShowFace = false; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	for(int j=0; jm_pBinaryArray[i][j] == 0) count++; 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 255; 
		} 
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) 
		{ 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 0; 
		} 
	} 
 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));			 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 水平方向直方图 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnHistogramH()  
{ 
	if(!method1->m_bBinaryReady) 
	{ 
		AfxMessageBox("请先计算二值图"); 
		return; 
	} 
	m_bShowFace = false; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	for(int j=0; jm_pBinaryArray[i][j] == 1) count++; 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 255; 
		} 
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) 
		{ 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 0; 
		} 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));		 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 头发的直方图 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnHistogramHair()  
{ 
	if(!method2->m_bBinaryOK) 
	{ 
		AfxMessageBox("请先计算二值图!"); 
		return; 
	} 
	m_bShowFace = false; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	for(int j=0; jm_pBinaryArray[i][j] == 1) count++; 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 255; 
		} 
		for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) 
		{ 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 0; 
		} 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));					 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 垂直方向的直方图 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnHistogramV()  
{ 
	if(!method1->m_bBinaryReady) 
	{ 
		AfxMessageBox("请先计算二值图"); 
		return; 
	} 
 
	m_bShowFace = false; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	for(int i=0; im_pBinaryArray[i][j] == 1) count++; 
			m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =	 
			m_tResPixelArray[i][j].rgbRed  = 255; 
		} 
		for(j=0; jCalLikeHood(); 
	for(int i=0; im_pLikeliHoodArray[i][j]*255); 
	} 
	MakeBitMap(); 
 
	SetCursor(LoadCursor(NULL,IDC_ARROW));	 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 标记眼睛区域 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnMarkEye()  
{ 
	int i,j; 
	if(!m_bFaceOK) 
	{ 
		AfxMessageBox("请先确定脸部区域"); 
		return; 
	} 
	//左右眼的水平区域 
	CPoint LeftEyeAreaH(-1,-1),RightEyeAreaH(-1,-1); 
	CPoint LeftEyeAreaV(-1,-1),RightEyeAreaV(-1,-1); 
 
	int nLeft,nRight,nTop,nBottom; 
 
	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0; 
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; 
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0; 
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; 
	//边缘检查 
	DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray); 
 
	/////////////////////////////////// 
	//确认两个眼睛的水平区域 
    ////////////////////////////////// 
	int nSlidWinWidth  = (m_rFaceRegion.right - m_rFaceRegion.left)/6/2; 
	int nSlidWinHeight = (m_rFaceRegion.bottom - m_rFaceRegion.top)/15/2; 
	int nMidFaceH = (m_rFaceRegion.right+m_rFaceRegion.left)/2; 
	int nMidFaceV = (m_rFaceRegion.bottom+m_rFaceRegion.top)/2; 
 
	int *tempArray = new int[m_nWndWidth];  
	for(i = 0; i m_rFaceRegion.top+6*nSlidWinHeight; i--) 
	for(j=m_rFaceRegion.left+nSlidWinWidth; j= nSlidWinWidth*nSlidWinHeight/3) 
		{ 
			m_tResPixelArray[i][j].rgbRed = 255; 
			tempArray[j] ++; 
		} 
	} 
 
	MakeBitMap(); 
	AfxMessageBox("眼睛的区域鉴别"); 
 
	CList myList1(sizeof(CPoint)); 
	CList myList2(sizeof(CPoint)); 
	int flag = 0; 
	CPoint tPoint(-1,-1); 
	for(i = 0; i 0 && flag ==0) 
		{ 
			tPoint.x = i; 
			flag = 1; 
		} 
		if(tempArray[i] == 0 && flag ==1) 
		{ 
			tPoint.y = i; 
			myList1.AddTail(tPoint); 
			flag = 0; 
		} 
	} 
	delete tempArray; 
	//去掉长度太小的候选者	 
	for(i=0; i=minVal) 
			myList2.AddTail(temp); 
	} 
	myList1.RemoveAll(); 
    //合并相邻很紧的区域 
	bool quit = 1; 
	while(quit) 
	{ 
		bool doJoin = false; 
		for(int i=0; i(m_rFaceRegion.right - m_rFaceRegion.left)/2) 
		{ 
			LeftEyeAreaH.x = t.x;  
			LeftEyeAreaH.y = t.x+(t.y-t.x)/3;  
			RightEyeAreaH.x = t.y-(t.y-t.x)/3; 
			RightEyeAreaH.y = t.y;  
		} 
		else 
		{ 
			AfxMessageBox("确认眼睛位置失败,请手动标定"); 
			return; 
		} 
	} 
	//仅有两个区域 
	else if(myList2.GetCount()==2) 
	{ 
		LeftEyeAreaH = myList2.GetHead(); 
		RightEyeAreaH = myList2.GetTail(); 
	} 
	else  //多于两个区域 
	{ 
		int ldis = -100000; 
		int rdis = 100000;	 
		for(i=0; i nMidFaceH) 
			{ 
				if(((temp.x+temp.y)/2-nMidFaceH)ldis) 
				{ 
					ldis = (temp.x+temp.y)/2-nMidFaceH; 
					LeftEyeAreaH = temp; 
				} 
			} 
		} 
	} 
	myList2.RemoveAll(); 
	/////////////////////////////////// 
	//确认两个眼睛的垂直区域 
    ////////////////////////////////// 
	//左眼 
	if(LeftEyeAreaH != CPoint(-1,-1)) 
	{ 
		int *tArray = new int[m_nWndHeight];  
		int i,j; 
		for(i = 0; i m_rFaceRegion.top+6*nSlidWinHeight; i--) 
		for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++) 
		if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0) 
			tArray[i] ++; 
 
		CList myListA(sizeof(CPoint)); 
		CList myListB(sizeof(CPoint)); 
		int flag = 0; 
		CPoint tPoint(-1,-1); 
		for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) 
		{ 
			if(tArray[i] > 0 && flag ==0) 
			{ 
				tPoint.x = i; 
				flag = 1; 
			} 
			if(tArray[i] == 0 && flag ==1) 
			{ 
				tPoint.y = i; 
				myListA.AddTail(tPoint); 
				flag = 0; 
			} 
		} 
		delete tArray; 
		//去掉长度太小的候选者	 
		for(i=0; i=minVal) 
				myListB.AddTail(temp); 
		} 
		myListA.RemoveAll(); 
		//合并相邻很紧的区域 
		bool quit = 1; 
		while(quit) 
		{ 
			bool doJoin = false; 
			for(int i=0; i= LeftEyeAreaV.y;i--) 
			for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++) 
			if(m_tResPixelArray[i][j].rgbGreen == 0) 
			{ 
				if(jm_LeftEyeRightCorner.x) 
				{ 
					m_LeftEyeRightCorner.x = j; 
					m_LeftEyeRightCorner.y = i; 
				} 
				sumX += j; 
				sumY += i; 
				sum++; 
			} 
 
			m_LeftEye.x = (int)(sumX/sum); 
			m_LeftEye.y = (int)(sumY/sum);	 
 
			m_bLeftEyeOK = TRUE;	 
			m_bLeftEyeLeftCornerOK = TRUE; 
			m_bLeftEyeRightCornerOK =TRUE; 
		} 
		myListB.RemoveAll(); 
	} 
	//右眼 
	if(RightEyeAreaH != CPoint(-1,-1)) 
	{ 
		int *tArray = new int[m_nWndHeight];  
		int i,j; 
		for(i = 0; i m_rFaceRegion.top+6*nSlidWinHeight; i--) 
		for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++) 
		if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0) 
			tArray[i] ++; 
 
		CList myListA(sizeof(CPoint)); 
		CList myListB(sizeof(CPoint)); 
		int flag = 0; 
		CPoint tPoint(-1,-1); 
		for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) 
		{ 
			if(tArray[i] > 0 && flag ==0) 
			{ 
				tPoint.x = i; 
				flag = 1; 
			} 
			if(tArray[i] == 0 && flag ==1) 
			{ 
				tPoint.y = i; 
				myListA.AddTail(tPoint); 
				flag = 0; 
			} 
		} 
		delete tArray; 
		//去掉长度太小的候选者	 
		for(i=0; i=minVal) 
				myListB.AddTail(temp); 
		} 
		myListA.RemoveAll(); 
		//合并相邻很紧的区域 
		bool quit = 1; 
		while(quit) 
		{ 
			bool doJoin = false; 
			for(int i=0; i LeftEyeAreaV.x && index > 0) 
				{ 
					index --; 
					tt = myListB.GetAt(myListB.FindIndex(myListB.GetCount()-index));  
				} 
				RightEyeAreaV = tt;		 
			} 
			 
			double sumX = 0.0; 
			double sumY = 0.0; 
			int sum = 0; 
			m_RightEyeLeftCorner.x = 100000; 
			m_RightEyeRightCorner.x = -1; 
 
			for(i=RightEyeAreaV.x; i>=RightEyeAreaV.y;i--) 
			for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++) 
			if(m_tResPixelArray[i][j].rgbGreen == 0) 
			{ 
				if(jm_RightEyeRightCorner.x) 
				{ 
					m_RightEyeRightCorner.x = j; 
					m_RightEyeRightCorner.y = i; 
				} 
				sumX += j; 
				sumY += i; 
				sum++; 
			} 
			m_RightEye.x = (int)(sumX/sum); 
			m_RightEye.y = (int)(sumY/sum); 
			 
			m_bRightEyeOK = TRUE; 
			m_bRightEyeLeftCornerOK = TRUE; 
			m_bRightEyeRightCornerOK =TRUE; 
 
		} 
		myListB.RemoveAll(); 
	} 
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
	MakeBitMap();		 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 第一种方法标记脸部区域 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnMarkFace1()  
{ 
	if(!method1->m_bBinaryReady) 
	{ 
		AfxMessageBox("请先计算二值化图!"); 
		return; 
	} 
	m_bShowFace = true; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	int *temp = new int[m_nWndWidth]; 
	int max = 0; 
	int pos = -1; 
	for(int j=0; jm_pBinaryArray[i][j] == 1) count++; 
		} 
		temp[j] = count; 
		if(count > max) 
		{ 
			max = count; 
			pos = j; 
		} 
	} 
	int left,right,l,top,bottom; 
	for(l=pos; l>=0; l--) 
	{ 
		if(temp[l]m_pBinaryArray[i][l] == 1) count++; 
		} 
		if(count>=(right-left)*0.5) 
		{ 
			top = i; 
			break; 
		} 
	} 
	bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5); 
 
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
 
	for(i=top;i<=bottom;i++) 
	{ 
		m_tResPixelArray[i][left].rgbBlue=255; 
		m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0; 
		m_tResPixelArray[i][right].rgbBlue=255; 
		m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0; 
	} 
	for(j=left;j<=right;j++) 
	{ 
		m_tResPixelArray[top][j].rgbBlue=255; 
		m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0; 
		m_tResPixelArray[bottom][j].rgbBlue=255; 
		m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0; 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));			 
 
	if(m_bFaceOK) 
	{ 
		ReplaceDlg dlg; 
		if(dlg.DoModal()==IDOK) 
		{ 
			CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
			CRect rect(left,top,right,bottom); 
			m_rFaceRegion = rect; 
			MakeBitMap(); 
		} 
	} 
	else 
	{ 
		m_bFaceOK = true; 
		CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
		CRect rect(left,top,right,bottom); 
		m_rFaceRegion = rect; 
		MakeBitMap(); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 第二种方法标记脸部区域 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnMarkFace2()  
{ 
	if(!method2->m_bBinaryOK) 
	{ 
		AfxMessageBox("请先计算二值化图"); 
		return; 
	} 
	m_bShowFace = true; 
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	int *numR,*numB, i, j, left,right,top,bottom; 
	int maxnumR = 0, maxnumB = 0; 
 
	numR = new int[m_nWndWidth]; 
	numB = new int[m_nWndWidth]; 
	for(j=0;jm_pBinaryArray[i][j] == 0) 
				countR++; 
			if(method2->m_pBinaryArray[i][j] == 1) 
				countB++; 
		} 
		if(countR > maxnumR) maxnumR = countR; 
		numR[j] = countR; 
		if(countB > maxnumB) maxnumB = countB; 
		numB[j] = countB; 
	} 
	CList myListR(sizeof(CPoint)); 
	CList myListB(sizeof(CPoint)); 
	CPoint tempR,tempB; 
	int flagR = 0,flagB = 0; 
	for(j=0;jmaxnumR/2) 
			{ 
				flagR = 1; 
				tempR.x = j;				 
			} 
		} 
		else 
		{ 
			if(numR[j]<=maxnumR/2 || j==m_nWndWidth-1) 
			{ 
				flagR = 0; 
				tempR.y = j; 
				myListR.AddTail(tempR); 
			} 
		} 
		if(flagB == 0) 
		{ 
			if(numB[j]>maxnumB/5) 
			{ 
				flagB = 1; 
				tempB.x = j; 
			} 
		} 
		else 
		{ 
			if(numB[j]<=maxnumB/5 || j==m_nWndWidth-1) 
			{ 
				flagB = 0; 
				tempB.y = j; 
				if(myListB.GetCount() > 1 && (tempB.x-myListB.GetTail().y)<20) 
					myListB.SetAt(myListB.GetTailPosition(),CPoint(myListB.GetTail().x,j)); 
				else 
				myListB.AddTail(tempB); 
			} 
		} 
 
	}	 
	if(numR!=NULL)delete numR; 
	if(numB!=NULL)delete numB; 
 
	int *hairmark, k; 
	hairmark = new int[m_nWndWidth]; 
	for(j=0;jm_nWndWidth/10) 
		{ 
			for(int t = temp.x;t<=temp.y;t++) 
			hairmark[t] = 1; 
		} 
	} 
 
	for(k=0;km_nWndWidth/10) 
		{ 
			for(int t=temp.x;t<=temp.y;t++) 
			{ 
				if(hairmark[t]==1) 
				{ 
					int endpos=t+(temp.y-temp.x)/5; 
					if(endpos > temp.y)endpos = temp.y; 
					int yes = 1; 
					for(int q=t;q<=endpos;q++) 
						if(hairmark[q]==0) yes = 0; 
					if(yes == 1) 
					{ 
						templeft = t; 
						break; 
					} 
				} 
			} 
			for(int p=temp.y;p>=temp.x;p--) 
			{ 
				if(hairmark[p]==1) 
				{ 
					int beginpos=p-(temp.y-temp.x)/5; 
					if(beginpos < temp.x)beginpos = temp.x; 
					int yes = 1; 
					for(int q=p;q>=beginpos;q--) 
						if(hairmark[q]==0) yes = 0; 
					if(yes == 1) 
					{ 
						tempright = p; 
						break; 
					} 
				} 
			} 
		} 
		if(templeft!=-1 && tempright!=-1) 
		{ 
			left = templeft; 
			right = tempright; 
			break; 
		} 
	} 
	if(hairmark !=NULL) delete hairmark; 
	myListR.RemoveAll(); 
	myListB.RemoveAll(); 
 
	if(left-m_nWndWidth/50>0) left-=(int)m_nWndWidth/50; 
	else left = 0; 
	if(right+m_nWndWidth/40>m_nWndWidth) right=m_nWndWidth-1; 
	else right += m_nWndWidth/40; 
 
	for(i=0; im_pBinaryArray[i][l] == 0) count++; 
		} 
		if(count>=(right-left)*0.5) 
		{ 
			top = i; 
			break; 
		} 
	} 
	bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5); 
 
	CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
 
	for(i=top;i<=bottom;i++) 
	{ 
		m_tResPixelArray[i][left].rgbBlue=255; 
		m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0; 
		m_tResPixelArray[i][right].rgbBlue=255; 
		m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0; 
	} 
	for(j=left;j<=right;j++) 
	{ 
		m_tResPixelArray[top][j].rgbBlue=255; 
		m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0; 
		m_tResPixelArray[bottom][j].rgbBlue=255; 
		m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0; 
	} 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));			 
 
	if(m_bFaceOK) 
	{ 
		ReplaceDlg dlg; 
		if(dlg.DoModal()==IDOK) 
		{ 
			CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
			CRect rect(left,top,right,bottom); 
			m_rFaceRegion = rect; 
			MakeBitMap(); 
		} 
	} 
	else 
	{ 
		m_bFaceOK = true; 
		CopyBitMap(m_tResPixelArray,m_tOriPixelArray); 
		CRect rect(left,top,right,bottom); 
		m_rFaceRegion = rect; 
		MakeBitMap(); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 标记嘴巴 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::OnBtnMarkMouse()  
{ 
	int i,j; 
	if(!(m_bLeftEyeOK&&m_bRightEyeOK)) 
	{ 
		AfxMessageBox("请先确定眼睛"); 
		return; 
	} 
	//左右眼的水平区域 
	int nLeft,nRight,nTop,nBottom; 
 
	nLeft	= m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0; 
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; 
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0; 
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; 
 
	SetPixelArray(m_tResPixelArray,0); 
	for(i=nTop; i<=nBottom; i++) 
	for(j=nLeft; j<=nRight; j++) 
	{ 
		BYTE R,G,B; 
		double temp,dlta; 
		R = m_tOriPixelArray[i][j].rgbRed; 
		G = m_tOriPixelArray[i][j].rgbGreen; 
		B = m_tOriPixelArray[i][j].rgbBlue; 
		if((R==G) && (G==B)) temp = 0; 
		else temp = 0.5*(2*R-G-B)/sqrt((R-G)*(R-G)+(R-B)*(G-B)); 
		dlta = acos(temp); 
		if(dlta < 0.2) 
		{ 
			m_tResPixelArray[i][j].rgbRed = 255;   
		} 
		else m_tResPixelArray[i][j].rgbRed = 0; 
	} 
 
	MakeBitMap(); 
	AfxMessageBox("嘴的肤色鉴定"); 
	//双目斜角 
	double tanThta; 
	if(m_RightEye.y == m_LeftEye.y) tanThta = 0; 
	else tanThta = (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); 
	//双目平均高度 
	int EyeV    = (m_RightEye.y + m_LeftEye.y)/2; 
	//可能的嘴的区域 
	int MouthUp   = (EyeV+1.0*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.0*EyesDis); 
	int MouthDown = (EyeV+1.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.5*EyesDis); 
 
 
	int* Y_Arry = new int[MouthDown-MouthUp]; 
	for(i =0 ;i < MouthDown-MouthUp ;i++) Y_Arry[i] = 0; 
	int* X_Arry = new int[EyesDis]; 
	for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0; 
	for(i = MouthUp ; i < MouthDown; i++) 
	for(j = m_LeftEye.x; j< m_RightEye.x; j++) 
	{ 
		if(m_tResPixelArray[i][j].rgbRed == 255) 
		{ 
			Y_Arry[i-MouthUp] ++; 
			X_Arry[j-m_LeftEye.x] ++; 
		} 
	} 
	 
	int maxY = 0; 
	for(i =0 ;i < MouthDown-MouthUp ;i++) 
	{ 
		if(Y_Arry[i]>maxY) 
		{ 
			maxY = Y_Arry[i]; 
			m_MidMouth.y =  i+MouthUp - (MouthDown-MouthUp)/10; 
		} 
	} 
	m_LeftMouthCorner.y  =(int)(m_MidMouth.y - tanThta*EyesDis/2); 
	m_RightMouthCorner.y =(int)(m_MidMouth.y + tanThta*EyesDis/2); 
	for(i =0 ;i < EyesDis ;i++) 
	{ 
		if(X_Arry[i]>0) 
		{ 
			m_LeftMouthCorner.x = i+m_LeftEye.x; 
			break; 
		} 
	} 
	for(i = EyesDis -1; i >=0 ;i--) 
	{ 
		if(X_Arry[i]>0) 
		{ 
			m_RightMouthCorner.x = m_LeftEye.x+i; 
			break; 
		} 
	} 
 
	//唇中点较薄 
	int min = 1000000; 
	for(i = (int)(3*EyesDis/7+0.5) ; i <= (int)(4*EyesDis/7+0.5);i++) 
	{ 
		if(X_Arry[i] 0 ? m_rFaceRegion.left-5:0; 
	nRight	= m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; 
	nTop	= m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0; 
	nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; 
 
	SetPixelArray(m_tResPixelArray,0); 
	for(i=nTop; i<=nBottom; i++) 
	for(j=nLeft; j<=nRight; j++) 
	{ 
		double Y; 
		Y = 0.30*m_tOriPixelArray[i][j].rgbRed+0.59*m_tOriPixelArray[i][j].rgbGreen 
			+0.11*m_tOriPixelArray[i][j].rgbBlue; 
		if(Y<100) 
		{ 
			m_tResPixelArray[i][j].rgbRed = 255;   
		} 
		else m_tResPixelArray[i][j].rgbRed = 0; 
	} 
 
	MakeBitMap(); 
	AfxMessageBox("鼻子的肤色鉴定"); 
	//双目斜角 
	double tanThta; 
	if(m_RightEye.y == m_LeftEye.y) tanThta = 0; 
	else tanThta = (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); 
	//双目平均高度 
	int EyeV    = (m_RightEye.y + m_LeftEye.y)/2; 
	//可能的鼻子的区域 
	int NoseUp   = (EyeV+0.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.5*EyesDis); 
	int NoseDown = (EyeV+0.8*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.8*EyesDis); 
 
	int* Y_Arry = new int[NoseDown-NoseUp]; 
	for(i =0 ;i < NoseDown-NoseUp ;i++) Y_Arry[i] = 0; 
 
	int* X_Arry = new int[EyesDis]; 
	for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0; 
 
	for(i = NoseUp ; i < NoseDown; i++) 
	for(j = m_LeftEye.x+EyesDis/5; j< m_RightEye.x-EyesDis/5; j++) 
	{ 
		if(m_tResPixelArray[i][j].rgbRed == 255) 
		{ 
			Y_Arry[i-NoseUp] ++; 
			X_Arry[j-m_LeftEye.x] ++; 
		} 
	} 
	 
	int maxY = 0; 
	for(i =0 ;i < NoseDown-NoseUp ;i++) 
	{ 
		if(Y_Arry[i]>maxY) 
		{ 
			maxY = Y_Arry[i]; 
			m_MidNose.y =  i+NoseUp; 
		} 
	} 
	m_LeftNostril.y  =(int)(m_MidNose.y - tanThta*EyesDis/2); 
	m_RightNostril.y =(int)(m_MidNose.y + tanThta*EyesDis/2); 
	for(i =0 ;i < EyesDis ;i++) 
	{ 
		if(X_Arry[i]>0) 
		{ 
			m_LeftNostril.x = i+m_LeftEye.x; 
			break; 
		} 
	} 
	for(i = EyesDis-1; i >=0 ;i--) 
	{ 
		if(X_Arry[i]>0) 
		{ 
			m_RightNostril.x = i+m_LeftEye.x; 
			break; 
		} 
	} 
	//唇中点较薄 
	int min = 1000000; 
	for(i = (int)(EyesDis/3+0.5) ; i <= (int)(2*EyesDis/3+0.5);i++) 
	{ 
		if(X_Arry[i]Open(strFile); 
	 
	m_nWndWidth = m_pMainDib->GetWidth(); 
	m_nWndHeight= m_pMainDib->GetHeight(); 
	m_sFileName = strFile; 
 
	m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 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)); 
	//获取像素的值 
	LoadOriPixel(m_pMainDib); 
	MakeBitMap(); 
	SetCursor(LoadCursor(NULL,IDC_ARROW));	 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
// 画图 
//////////////////////////////////////////////////////////////////////////////// 
void CFaceDetectDlg::MyDraw() 
{ 
	CRect rc; 
	pDCShow->GetWindow()->GetClientRect(&rc); 
	pDCShow->Rectangle(&rc); 
	CDC dc; 
	CBitmap *pOldBitmap; 
	dc.CreateCompatibleDC(pDCShow); 
	pOldBitmap=dc.SelectObject(m_pResMap); 
	pDCShow->StretchBlt(0,0,m_nWndWidth,m_nWndHeight,&dc,0,0,m_nWndWidth,m_nWndHeight,SRCCOPY); 
	dc.SelectObject(pOldBitmap); 
	dc.DeleteDC(); 
}