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();
}