FaceDetectDlg.cpp
上传用户:joy_gong
上传日期:2020-11-30
资源大小:459k
文件大小:44k
源码类别:

生物技术

开发平台:

Visual C++

  1. // FaceDetectDlg.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "FaceDetect.h"
  5. #include "FaceDetectDlg.h"
  6. #include "ReplaceDlg.h"
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. #include "AddSampleDlg.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. // CAboutDlg dialog used for App About
  15. class CAboutDlg : public CDialog
  16. {
  17. public:
  18. CAboutDlg();
  19. // Dialog Data
  20. //{{AFX_DATA(CAboutDlg)
  21. enum { IDD = IDD_ABOUTBOX };
  22. //}}AFX_DATA
  23. // ClassWizard generated virtual function overrides
  24. //{{AFX_VIRTUAL(CAboutDlg)
  25. protected:
  26. virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  27. //}}AFX_VIRTUAL
  28. // Implementation
  29. protected:
  30. //{{AFX_MSG(CAboutDlg)
  31. //}}AFX_MSG
  32. DECLARE_MESSAGE_MAP()
  33. };
  34. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  35. {
  36. //{{AFX_DATA_INIT(CAboutDlg)
  37. //}}AFX_DATA_INIT
  38. }
  39. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  40. {
  41. CDialog::DoDataExchange(pDX);
  42. //{{AFX_DATA_MAP(CAboutDlg)
  43. //}}AFX_DATA_MAP
  44. }
  45. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  46. //{{AFX_MSG_MAP(CAboutDlg)
  47. // No message handlers
  48. //}}AFX_MSG_MAP
  49. END_MESSAGE_MAP()
  50. /////////////////////////////////////////////////////////////////////////////
  51. // CFaceDetectDlg dialog
  52. CFaceDetectDlg::CFaceDetectDlg(CWnd* pParent /*=NULL*/)
  53. : CDialog(CFaceDetectDlg::IDD, pParent)
  54. {
  55. //{{AFX_DATA_INIT(CFaceDetectDlg)
  56. // NOTE: the ClassWizard will add member initialization here
  57. //}}AFX_DATA_INIT
  58. // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  59. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  60. }
  61. void CFaceDetectDlg::DoDataExchange(CDataExchange* pDX)
  62. {
  63. CDialog::DoDataExchange(pDX);
  64. //{{AFX_DATA_MAP(CFaceDetectDlg)
  65. // NOTE: the ClassWizard will add DDX and DDV calls here
  66. //}}AFX_DATA_MAP
  67. }
  68. BEGIN_MESSAGE_MAP(CFaceDetectDlg, CDialog)
  69. //{{AFX_MSG_MAP(CFaceDetectDlg)
  70. ON_WM_SYSCOMMAND()
  71. ON_WM_PAINT()
  72. ON_WM_QUERYDRAGICON()
  73. ON_BN_CLICKED(IDC_BTN_BINARY, OnBtnBinary)
  74. ON_BN_CLICKED(IDC_BTN_EDGE, OnBtnEdge)
  75. ON_BN_CLICKED(IDC_BTN_FACEHAIR, OnBtnFacehair)
  76. ON_BN_CLICKED(IDC_BTN_HISTOGRAM_FACE, OnBtnHistogramFace)
  77. ON_BN_CLICKED(IDC_BTN_HISTOGRAM_H, OnBtnHistogramH)
  78. ON_BN_CLICKED(IDC_BTN_HISTOGRAM_HAIR, OnBtnHistogramHair)
  79. ON_BN_CLICKED(IDC_BTN_HISTOGRAM_V, OnBtnHistogramV)
  80. ON_BN_CLICKED(IDC_BTN_LIKEHOOD, OnBtnLikehood)
  81. ON_BN_CLICKED(IDC_BTN_MARK_EYE, OnBtnMarkEye)
  82. ON_BN_CLICKED(IDC_BTN_MARK_FACE_1, OnBtnMarkFace1)
  83. ON_BN_CLICKED(IDC_BTN_MARK_FACE_2, OnBtnMarkFace2)
  84. ON_BN_CLICKED(IDC_BTN_MARK_MOUSE, OnBtnMarkMouse)
  85. ON_BN_CLICKED(IDC_BTN_MARK_NOSE, OnBtnMarkNose)
  86. ON_BN_CLICKED(IDC_BTN_OPENFILE, OnBtnOpenfile)
  87. //}}AFX_MSG_MAP
  88. END_MESSAGE_MAP()
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CFaceDetectDlg message handlers
  91. BOOL CFaceDetectDlg::OnInitDialog()
  92. {
  93. CDialog::OnInitDialog();
  94. // Add "About..." menu item to system menu.
  95. // IDM_ABOUTBOX must be in the system command range.
  96. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  97. ASSERT(IDM_ABOUTBOX < 0xF000);
  98. CMenu* pSysMenu = GetSystemMenu(FALSE);
  99. if (pSysMenu != NULL)
  100. {
  101. CString strAboutMenu;
  102. strAboutMenu.LoadString(IDS_ABOUTBOX);
  103. if (!strAboutMenu.IsEmpty())
  104. {
  105. pSysMenu->AppendMenu(MF_SEPARATOR);
  106. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  107. }
  108. }
  109. // Set the icon for this dialog.  The framework does this automatically
  110. //  when the application's main window is not a dialog
  111. SetIcon(m_hIcon, TRUE); // Set big icon
  112. SetIcon(m_hIcon, FALSE); // Set small icon
  113. // TODO: Add extra initialization here
  114. CWnd *pWnd0= GetDlgItem(IDC_BMPSHOW);
  115. pDCShow = pWnd0->GetDC();
  116. m_pMainDib = new CDib();
  117. m_tOriPixelArray = NULL;
  118. m_tResPixelArray = NULL;
  119. m_pResMap = NULL;
  120. m_nWndWidth = 0;
  121. m_nWndHeight= 0;
  122. m_sFileName = "";
  123. m_bSelectByMan = false;
  124. m_bLBottonDown = false;
  125. m_ManLeft = -1;
  126. m_ManRight = -1;
  127. m_ManTop = -1;
  128. m_ManBottom = -1;
  129. m_bFaceOK = false;
  130. m_bShowFace = false;
  131. m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0;
  132. m_bManualMarkFacial = false;
  133. m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK =
  134. m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = 
  135. m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false;
  136. m_bMidMouthOK = m_bMidNoseOK = false;
  137. m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = 
  138. m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner =
  139. m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1);
  140. return TRUE;  // return TRUE  unless you set the focus to a control
  141. }
  142. void CFaceDetectDlg::OnSysCommand(UINT nID, LPARAM lParam)
  143. {
  144. if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  145. {
  146. CAboutDlg dlgAbout;
  147. dlgAbout.DoModal();
  148. }
  149. else
  150. {
  151. CDialog::OnSysCommand(nID, lParam);
  152. }
  153. }
  154. // If you add a minimize button to your dialog, you will need the code below
  155. //  to draw the icon.  For MFC applications using the document/view model,
  156. //  this is automatically done for you by the framework.
  157. void CFaceDetectDlg::OnPaint() 
  158. {
  159. if (IsIconic())
  160. {
  161. CPaintDC dc(this); // device context for painting
  162. SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  163. // Center icon in client rectangle
  164. int cxIcon = GetSystemMetrics(SM_CXICON);
  165. int cyIcon = GetSystemMetrics(SM_CYICON);
  166. CRect rect;
  167. GetClientRect(&rect);
  168. int x = (rect.Width() - cxIcon + 1) / 2;
  169. int y = (rect.Height() - cyIcon + 1) / 2;
  170. // Draw the icon
  171. dc.DrawIcon(x, y, m_hIcon);
  172. if(m_tResPixelArray==NULL) return;
  173. }
  174. else
  175. {
  176. CDialog::OnPaint();
  177. }
  178. }
  179. // The system calls this to obtain the cursor to display while the user drags
  180. //  the minimized window.
  181. HCURSOR CFaceDetectDlg::OnQueryDragIcon()
  182. {
  183. return (HCURSOR) m_hIcon;
  184. }
  185. ////////////////////////////////////////////////////////////////////////////////
  186. // 画十字形标记
  187. // 参数:  pDC-CDC指针
  188. //         point-要画的点的坐标
  189. //         crColor-标记得颜色
  190. ////////////////////////////////////////////////////////////////////////////////
  191. void CFaceDetectDlg::DrawCross(CDC *pDC, CPoint point, COLORREF crColor)
  192. {
  193. CPen pen,*oldPen;
  194. pen.CreatePen(PS_SOLID,1,crColor);
  195. oldPen = (CPen*)pDC->SelectObject(&pen);
  196. pDC->MoveTo(point.x-7,point.y);
  197. pDC->LineTo(point.x+7,point.y);
  198. pDC->MoveTo(point.x,point.y-7);
  199. pDC->LineTo(point.x,point.y+7);
  200. pDC->SelectObject(oldPen);
  201. pen.DeleteObject();
  202. }
  203. ////////////////////////////////////////////////////////////////////////////////
  204. // 拷贝位图
  205. // 参数:  dest-目标位图指针
  206. //         source-源位图指针
  207. ////////////////////////////////////////////////////////////////////////////////
  208. bool CFaceDetectDlg::CopyBitMap(RGBQUAD **dest, RGBQUAD **source)
  209. {
  210. if(source==NULL || dest==NULL) 
  211. return false;
  212. for(int i=0; i<m_nWndHeight; i++)
  213. for(int j=0; j<m_nWndWidth; j++)
  214. dest[i][j]=source[i][j];
  215. return true;
  216. }
  217. ////////////////////////////////////////////////////////////////////////////////
  218. // 生成新的位图
  219. ////////////////////////////////////////////////////////////////////////////////
  220. void CFaceDetectDlg::MakeBitMap()
  221. {
  222. CClientDC ClientDC(pDCShow->GetWindow());
  223. if(m_pResMap!=NULL) delete m_pResMap;
  224. m_pResMap=new CBitmap();
  225. m_pResMap->CreateCompatibleBitmap(&ClientDC,m_nWndWidth,m_nWndHeight);
  226. CDC  dc;
  227. dc.CreateCompatibleDC(&ClientDC);
  228. dc.SelectObject(m_pResMap);
  229. for(int i=0; i<m_nWndHeight; i++)
  230. for(int j=0; j<m_nWndWidth; j++)
  231. dc.SetPixelV(j,i,RGB(m_tResPixelArray[i][j].rgbRed,m_tResPixelArray[i][j].rgbGreen,m_tResPixelArray[i][j].rgbBlue));
  232. if(m_bFaceOK && m_bShowFace)
  233. {
  234. CBrush Pen;
  235. Pen.CreateSolidBrush(RGB(255,0,0));
  236. dc.FrameRect(m_rFaceRegion,&Pen);
  237.   Pen.DeleteObject();
  238. }
  239. if(m_bLeftEyeOK) DrawCross(&dc,m_LeftEye,RGB(255,0,0));
  240. if(m_bRightEyeOK) DrawCross(&dc,m_RightEye,RGB(255,0,0));
  241. if(m_bLeftEyeLeftCornerOK) DrawCross(&dc,m_LeftEyeLeftCorner,RGB(255,0,255));
  242. if(m_bLeftEyeRightCornerOK) DrawCross(&dc,m_LeftEyeRightCorner,RGB(255,255,0));
  243. if(m_bRightEyeLeftCornerOK) DrawCross(&dc,m_RightEyeLeftCorner,RGB(255,0,255));
  244. if(m_bRightEyeRightCornerOK) DrawCross(&dc,m_RightEyeRightCorner,RGB(255,255,0));
  245. if(m_bLeftNostrilOK) DrawCross(&dc,m_LeftNostril,RGB(0,255,0));
  246. if(m_bRightNostrilOK) DrawCross(&dc,m_RightNostril,RGB(0,255,0));
  247. if(m_bMidNoseOK) DrawCross(&dc,m_MidNose,RGB(0,255,0));
  248. if(m_bLeftMouthCornerOK) DrawCross(&dc,m_LeftMouthCorner,RGB(0,0,255));
  249. if(m_bRightMouthCornerOK) DrawCross(&dc,m_RightMouthCorner,RGB(0,0,255));
  250. if(m_bMidMouthOK) DrawCross(&dc,m_MidMouth,RGB(0,0,255));
  251. dc.DeleteDC();
  252. MyDraw();
  253. }
  254. ////////////////////////////////////////////////////////////////////////////////////
  255. //读原图的数据
  256. ////////////////////////////////////////////////////////////////////////////////////
  257. void CFaceDetectDlg::LoadOriPixel(CDib *pDib)
  258. {
  259. BYTE *colorTable;
  260. colorTable = (BYTE *)pDib->m_pDibBits;
  261. int byteBitCount  = pDib->GetBiBitCount()/8;
  262. m_tOriPixelArray  = new RGBQUAD*[m_nWndHeight];
  263. m_tResPixelArray  = new RGBQUAD*[m_nWndHeight];
  264. for(int l=0 ; l<m_nWndHeight; l++)
  265. {
  266. m_tOriPixelArray[l] = new RGBQUAD[m_nWndWidth];
  267. m_tResPixelArray[l] = new RGBQUAD[m_nWndWidth];
  268. }
  269. int count = 0;
  270. for(int i=m_nWndHeight-1; i>=0; i--)
  271. {
  272. for(int j=0; j<m_nWndWidth; j++)
  273. {
  274. m_tOriPixelArray[i][j].rgbBlue =colorTable[count++];
  275. m_tOriPixelArray[i][j].rgbGreen=colorTable[count++];
  276. m_tOriPixelArray[i][j].rgbRed  =colorTable[count++];
  277. m_tOriPixelArray[i][j].rgbReserved = 0;
  278. m_tResPixelArray[i][j]=m_tOriPixelArray[i][j];
  279. count += byteBitCount-3;
  280. }
  281. count += (4-(m_nWndWidth*byteBitCount)%4)%4;
  282. }
  283. method1 = new CLikelyHood(m_tOriPixelArray,m_nWndWidth,m_nWndHeight);
  284. method2 = new CHairFace(m_tOriPixelArray,m_nWndWidth,m_nWndHeight);
  285. }
  286. ////////////////////////////////////////////////////////////////////////////////
  287. // 给位图赋值
  288. // 参数:  target-目标位图指针
  289. //         Val-要赋予的值
  290. ////////////////////////////////////////////////////////////////////////////////
  291. void CFaceDetectDlg::SetPixelArray(RGBQUAD **target, int Val)
  292. {
  293. for(int i=0; i<m_nWndHeight; i++)
  294. for(int j=0; j<m_nWndWidth; j++)
  295. {
  296. target[i][j].rgbRed =  target[i][j].rgbBlue = target[i][j].rgbGreen = Val;
  297. }
  298. }
  299. ////////////////////////////////////////////////////////////////////////////////
  300. // 边界检测
  301. ////////////////////////////////////////////////////////////////////////////////
  302. void CFaceDetectDlg::DoLOG(int left, int right, int top, int bottom, RGBQUAD **source, RGBQUAD **target)
  303. {
  304. int i,j;
  305. double **result;  
  306. result = new double*[m_nWndHeight];
  307. for(int l=0 ; l<m_nWndHeight; l++)
  308. {
  309. result[l] = new double[m_nWndWidth];
  310. for(j=0; j<m_nWndWidth; j++)
  311. result[l][j] = source[l][j].rgbRed;
  312. }
  313. for(i=0; i<m_nWndHeight; i++)
  314. for(j=0; j<m_nWndWidth; j++)
  315. {
  316. double r,g,temp;
  317. temp = source[i][j].rgbGreen+source[i][j].rgbRed+source[i][j].rgbBlue;
  318. r = (double)source[i][j].rgbRed/temp;
  319. g = (double)source[i][j].rgbGreen/temp;
  320. if(g<0.398 && g > 0.246 && r<0.664 && r>0.233 && r>g && g>=0.5*(1-r))
  321. {
  322. target[i][j].rgbRed = 255;  //face
  323. }
  324. else target[i][j].rgbRed = 0;
  325. }
  326. for(i=top+2; i<bottom-2; i++)
  327. for(j=left+2; j<right-2; j++)
  328. {
  329. result[i][j] =  
  330.      (0-2.0/24.0)*((unsigned char)target[i-2][j-2].rgbRed) + 
  331.                  (0-4.0/24.0)*((unsigned char)target[i-2][j-1].rgbRed) + 
  332.      (0-4.0/24.0)*((unsigned char)target[i-2][j].rgbRed)   +
  333.      (0-4.0/24.0)*((unsigned char)target[i-2][j+1].rgbRed) +
  334.      (0-2.0/24.0)*((unsigned char)target[i-2][j+2].rgbRed) +
  335.  (0-4.0/24.0)*((unsigned char)target[i-1][j-2].rgbRed) + 
  336.  (8.0/24.0)  *((unsigned char)target[i-1][j].rgbRed)   +
  337.  (0-4.0/24.0)*((unsigned char)target[i-1][j+2].rgbRed) +
  338.  (0-4.0/24.0)*((unsigned char)target[i][j-2].rgbRed)   + 
  339.  (8.0/24.0)  *((unsigned char)target[i][j-1].rgbRed)   + 
  340.  (1.0)       *((unsigned char)target[i][j].rgbRed)     +
  341.  (8.0/24.0)  *((unsigned char)target[i][j+1].rgbRed)   +
  342.  (0-4.0/24.0)*((unsigned char)target[i][j+2].rgbRed)   +
  343.  (0-4.0/24.0)*((unsigned char)target[i+1][j-2].rgbRed) + 
  344.  (8.0/24.0)  *((unsigned char)target[i+1][j].rgbRed)   +
  345.  (0-4.0/24.0)*((unsigned char)target[i+1][j+2].rgbRed) +
  346.  (0-2.0/24.0)*((unsigned char)target[i+2][j-2].rgbRed) + 
  347.  (0-4.0/24.0)*((unsigned char)target[i+2][j-1].rgbRed) + 
  348.  (0-4.0/24.0)*((unsigned char)target[i+2][j].rgbRed)   +
  349.  (0-4.0/24.0)*((unsigned char)target[i+2][j+1].rgbRed) +
  350.  (0-2.0/24.0)*((unsigned char)target[i+2][j+2].rgbRed);
  351. }
  352. SetPixelArray(target,255);
  353. for(i=top+1; i<bottom-1; i++)
  354. for(j=left+1; j<right-1; j++)
  355. {
  356. int positive = 0;   
  357. int negtive  = 0;
  358. for(int m=-1;m<=1;m++)
  359. for(int n=-1;n<=1;n++)
  360. if(m!=0 || n!=0)
  361. {
  362. if(result[i+m][j+n]<-5)negtive++;
  363. if(result[i+m][j+n]>=5)positive++;
  364. }
  365. if(positive>2 && negtive>2) 
  366. {
  367. target[i][j].rgbBlue = target[i][j].rgbGreen = target[i][j].rgbRed = 0;
  368. }
  369. }
  370. if(result!=NULL)
  371. {
  372. for (int i=0 ;i<m_nWndHeight;i++)
  373. if(result[i]!=NULL) delete result[i];
  374. delete result;
  375. }
  376. }
  377. ////////////////////////////////////////////////////////////////////////////////
  378. // 二值化
  379. ////////////////////////////////////////////////////////////////////////////////
  380. void CFaceDetectDlg::OnBtnBinary() 
  381. {
  382. SetCursor(LoadCursor(NULL,IDC_WAIT));
  383. if(!method1->CalBinary())
  384. {
  385. AfxMessageBox("请先计算相似度!");
  386. SetCursor(LoadCursor(NULL,IDC_ARROW));
  387. return;
  388. }
  389. m_bShowFace = false;
  390. for(int i=0; i<m_nWndHeight; i++)
  391. for(int j=0; j<m_nWndWidth;  j++)
  392. {
  393. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  394. m_tResPixelArray[i][j].rgbRed  = (int)(method1->m_pBinaryArray[i][j]*255);
  395. }
  396. MakeBitMap();
  397. SetCursor(LoadCursor(NULL,IDC_ARROW));
  398. MyDraw();
  399. }
  400. ////////////////////////////////////////////////////////////////////////////////
  401. // 边缘提取
  402. ////////////////////////////////////////////////////////////////////////////////
  403. void CFaceDetectDlg::OnBtnEdge() 
  404. {
  405. if(!m_bFaceOK)
  406. {
  407. AfxMessageBox("请先确定脸部区域");
  408. return;
  409. }
  410. //左右眼的水平区域
  411. int nLeft,nRight,nTop,nBottom;
  412. nLeft = m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
  413. nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
  414. nTop = m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
  415. nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
  416. //边缘检查
  417. DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray);
  418. MakeBitMap();
  419. }
  420. ////////////////////////////////////////////////////////////////////////////////
  421. // 求取头发和脸部区域
  422. ////////////////////////////////////////////////////////////////////////////////
  423. void CFaceDetectDlg::OnBtnFacehair() 
  424. {
  425. m_bShowFace = false;
  426. SetCursor(LoadCursor(NULL,IDC_WAIT));
  427. method2->MarkHairFace();
  428. for(int i=0; i<m_nWndHeight; i++)
  429. for(int j=0; j<m_nWndWidth;  j++)
  430. {
  431. switch(method2->m_pBinaryArray[i][j])
  432. {
  433. case 0:
  434. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = 0;
  435. m_tResPixelArray[i][j].rgbRed  = 255;
  436. break;
  437. case 1:
  438. m_tResPixelArray[i][j].rgbBlue = 255;
  439. m_tResPixelArray[i][j].rgbGreen=m_tResPixelArray[i][j].rgbRed=0;
  440. break;
  441. case 2:
  442. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  443. m_tResPixelArray[i][j].rgbRed  = 0;
  444. break;
  445. }
  446. }
  447. MakeBitMap();
  448. SetCursor(LoadCursor(NULL,IDC_ARROW));
  449. }
  450. ////////////////////////////////////////////////////////////////////////////////
  451. // 脸部区域直方图
  452. ////////////////////////////////////////////////////////////////////////////////
  453. void CFaceDetectDlg::OnBtnHistogramFace() 
  454. {
  455. if(!method2->m_bBinaryOK)
  456. {
  457. AfxMessageBox("请先计算二值化图!");
  458. return;
  459. }
  460. m_bShowFace = false;
  461. SetCursor(LoadCursor(NULL,IDC_WAIT));
  462. for(int j=0; j<m_nWndWidth;  j++)
  463. {
  464. int count = 0;
  465. for(int i=0; i<m_nWndHeight; i++)
  466. {
  467. if(method2->m_pBinaryArray[i][j] == 0) count++;
  468. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  469. m_tResPixelArray[i][j].rgbRed  = 255;
  470. }
  471. for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
  472. {
  473. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  474. m_tResPixelArray[i][j].rgbRed  = 0;
  475. }
  476. }
  477. MakeBitMap();
  478. SetCursor(LoadCursor(NULL,IDC_ARROW));
  479. }
  480. ////////////////////////////////////////////////////////////////////////////////
  481. // 水平方向直方图
  482. ////////////////////////////////////////////////////////////////////////////////
  483. void CFaceDetectDlg::OnBtnHistogramH() 
  484. {
  485. if(!method1->m_bBinaryReady)
  486. {
  487. AfxMessageBox("请先计算二值图");
  488. return;
  489. }
  490. m_bShowFace = false;
  491. SetCursor(LoadCursor(NULL,IDC_WAIT));
  492. for(int j=0; j<m_nWndWidth;  j++)
  493. {
  494. int count = 0;
  495. for(int i=0; i<m_nWndHeight; i++)
  496. {
  497. if(method1->m_pBinaryArray[i][j] == 1) count++;
  498. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  499. m_tResPixelArray[i][j].rgbRed  = 255;
  500. }
  501. for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
  502. {
  503. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  504. m_tResPixelArray[i][j].rgbRed  = 0;
  505. }
  506. }
  507. MakeBitMap();
  508. SetCursor(LoadCursor(NULL,IDC_ARROW));
  509. }
  510. ////////////////////////////////////////////////////////////////////////////////
  511. // 头发的直方图
  512. ////////////////////////////////////////////////////////////////////////////////
  513. void CFaceDetectDlg::OnBtnHistogramHair() 
  514. {
  515. if(!method2->m_bBinaryOK)
  516. {
  517. AfxMessageBox("请先计算二值图!");
  518. return;
  519. }
  520. m_bShowFace = false;
  521. SetCursor(LoadCursor(NULL,IDC_WAIT));
  522. for(int j=0; j<m_nWndWidth;  j++)
  523. {
  524. int count = 0;
  525. for(int i=0; i<m_nWndHeight; i++)
  526. {
  527. if(method2->m_pBinaryArray[i][j] == 1) count++;
  528. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  529. m_tResPixelArray[i][j].rgbRed  = 255;
  530. }
  531. for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--)
  532. {
  533. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  534. m_tResPixelArray[i][j].rgbRed  = 0;
  535. }
  536. }
  537. MakeBitMap();
  538. SetCursor(LoadCursor(NULL,IDC_ARROW));
  539. }
  540. ////////////////////////////////////////////////////////////////////////////////
  541. // 垂直方向的直方图
  542. ////////////////////////////////////////////////////////////////////////////////
  543. void CFaceDetectDlg::OnBtnHistogramV() 
  544. {
  545. if(!method1->m_bBinaryReady)
  546. {
  547. AfxMessageBox("请先计算二值图");
  548. return;
  549. }
  550. m_bShowFace = false;
  551. SetCursor(LoadCursor(NULL,IDC_WAIT));
  552. for(int i=0; i<m_nWndHeight; i++)
  553. {
  554. int count = 0;
  555. for(int j=0; j<m_nWndWidth;  j++)
  556. {
  557. if(method1->m_pBinaryArray[i][j] == 1) count++;
  558. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  559. m_tResPixelArray[i][j].rgbRed  = 255;
  560. }
  561. for(j=0; j<count;  j++)
  562. {
  563. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  564. m_tResPixelArray[i][j].rgbRed  = 0;
  565. }
  566. }
  567. MakeBitMap();
  568. SetCursor(LoadCursor(NULL,IDC_ARROW));
  569. }
  570. ////////////////////////////////////////////////////////////////////////////////
  571. // 计算相似度
  572. ////////////////////////////////////////////////////////////////////////////////
  573. void CFaceDetectDlg::OnBtnLikehood() 
  574. {
  575. m_bShowFace = false;
  576. SetCursor(LoadCursor(NULL,IDC_WAIT));
  577. method1->CalLikeHood();
  578. for(int i=0; i<m_nWndHeight; i++)
  579. for(int j=0; j<m_nWndWidth;  j++)
  580. {
  581. m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen =
  582. m_tResPixelArray[i][j].rgbRed  = (int)(method1->m_pLikeliHoodArray[i][j]*255);
  583. }
  584. MakeBitMap();
  585. SetCursor(LoadCursor(NULL,IDC_ARROW));
  586. }
  587. ////////////////////////////////////////////////////////////////////////////////
  588. // 标记眼睛区域
  589. ////////////////////////////////////////////////////////////////////////////////
  590. void CFaceDetectDlg::OnBtnMarkEye() 
  591. {
  592. int i,j;
  593. if(!m_bFaceOK)
  594. {
  595. AfxMessageBox("请先确定脸部区域");
  596. return;
  597. }
  598. //左右眼的水平区域
  599. CPoint LeftEyeAreaH(-1,-1),RightEyeAreaH(-1,-1);
  600. CPoint LeftEyeAreaV(-1,-1),RightEyeAreaV(-1,-1);
  601. int nLeft,nRight,nTop,nBottom;
  602. nLeft = m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
  603. nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
  604. nTop = m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
  605. nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
  606. //边缘检查
  607. DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray);
  608. ///////////////////////////////////
  609. //确认两个眼睛的水平区域
  610.     //////////////////////////////////
  611. int nSlidWinWidth  = (m_rFaceRegion.right - m_rFaceRegion.left)/6/2;
  612. int nSlidWinHeight = (m_rFaceRegion.bottom - m_rFaceRegion.top)/15/2;
  613. int nMidFaceH = (m_rFaceRegion.right+m_rFaceRegion.left)/2;
  614. int nMidFaceV = (m_rFaceRegion.bottom+m_rFaceRegion.top)/2;
  615. int *tempArray = new int[m_nWndWidth]; 
  616. for(i = 0; i<m_nWndWidth; i++) tempArray[i] = 0;
  617. for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
  618. for(j=m_rFaceRegion.left+nSlidWinWidth; j<m_rFaceRegion.right-nSlidWinWidth; j++)
  619. {
  620. int count = 0;
  621. for(int p= -nSlidWinHeight ;p<nSlidWinHeight;p++)
  622. for(int q= -nSlidWinWidth ;q<nSlidWinWidth;q++)
  623. {
  624. if(m_tResPixelArray[i+p][j+q].rgbRed == 0) count++;
  625. }
  626. if(count >= nSlidWinWidth*nSlidWinHeight/3)
  627. {
  628. m_tResPixelArray[i][j].rgbRed = 255;
  629. tempArray[j] ++;
  630. }
  631. }
  632. MakeBitMap();
  633. AfxMessageBox("眼睛的区域鉴别");
  634. CList<CPoint,CPoint&> myList1(sizeof(CPoint));
  635. CList<CPoint,CPoint&> myList2(sizeof(CPoint));
  636. int flag = 0;
  637. CPoint tPoint(-1,-1);
  638. for(i = 0; i<m_nWndWidth; i++)
  639. {
  640. if(tempArray[i] > 0 && flag ==0)
  641. {
  642. tPoint.x = i;
  643. flag = 1;
  644. }
  645. if(tempArray[i] == 0 && flag ==1)
  646. {
  647. tPoint.y = i;
  648. myList1.AddTail(tPoint);
  649. flag = 0;
  650. }
  651. }
  652. delete tempArray;
  653. //去掉长度太小的候选者
  654. for(i=0; i<myList1.GetCount();i++)
  655. {
  656. CPoint temp(-1,-1);
  657. temp = myList1.GetAt(myList1.FindIndex(i));
  658. int minVal = (m_rFaceRegion.right - m_rFaceRegion.left)/20;
  659. if((temp.y-temp.x)>=minVal)
  660. myList2.AddTail(temp);
  661. }
  662. myList1.RemoveAll();
  663.     //合并相邻很紧的区域
  664. bool quit = 1;
  665. while(quit)
  666. {
  667. bool doJoin = false;
  668. for(int i=0; i<myList2.GetCount()-1;i++)
  669. {
  670. CPoint temp1(-1,-1),temp2(-1,-1);
  671. temp1 = myList2.GetAt(myList2.FindIndex(i));
  672. temp2 = myList2.GetAt(myList2.FindIndex(i+1));
  673. if((temp2.x-temp1.y)<=(m_rFaceRegion.right - m_rFaceRegion.left)/40)
  674. {
  675. temp1.y = temp2.y;
  676. myList2.RemoveAt(myList2.FindIndex(i));
  677. myList2.RemoveAt(myList2.FindIndex(i));
  678. if(i == 0) myList2.AddHead(temp1);
  679. else     myList2.InsertAfter(myList2.FindIndex(i-1),temp1);
  680. doJoin = true;
  681. break;
  682. }
  683. }
  684. if(!doJoin) quit = 0;
  685. }
  686. //没有找到眼睛区域
  687. if(myList2.GetCount()<2) 
  688. {
  689. CPoint t=myList2.GetHead();
  690. if((t.y-t.x)>(m_rFaceRegion.right - m_rFaceRegion.left)/2)
  691. {
  692. LeftEyeAreaH.x = t.x; 
  693. LeftEyeAreaH.y = t.x+(t.y-t.x)/3; 
  694. RightEyeAreaH.x = t.y-(t.y-t.x)/3;
  695. RightEyeAreaH.y = t.y; 
  696. }
  697. else
  698. {
  699. AfxMessageBox("确认眼睛位置失败,请手动标定");
  700. return;
  701. }
  702. }
  703. //仅有两个区域
  704. else if(myList2.GetCount()==2)
  705. {
  706. LeftEyeAreaH = myList2.GetHead();
  707. RightEyeAreaH = myList2.GetTail();
  708. }
  709. else  //多于两个区域
  710. {
  711. int ldis = -100000;
  712. int rdis = 100000;
  713. for(i=0; i<myList2.GetCount();i++)
  714. {
  715. CPoint temp(-1,-1);
  716. temp = myList2.GetAt(myList2.FindIndex(i));
  717. //右眼
  718. if((temp.x+temp.y)/2 > nMidFaceH)
  719. {
  720. if(((temp.x+temp.y)/2-nMidFaceH)<rdis)
  721. {
  722. rdis = (temp.x+temp.y)/2-nMidFaceH;
  723. RightEyeAreaH = temp;
  724. }
  725. }
  726. //左眼
  727. else
  728. {
  729. if(((temp.x+temp.y)/2-nMidFaceH)>ldis)
  730. {
  731. ldis = (temp.x+temp.y)/2-nMidFaceH;
  732. LeftEyeAreaH = temp;
  733. }
  734. }
  735. }
  736. }
  737. myList2.RemoveAll();
  738. ///////////////////////////////////
  739. //确认两个眼睛的垂直区域
  740.     //////////////////////////////////
  741. //左眼
  742. if(LeftEyeAreaH != CPoint(-1,-1))
  743. {
  744. int *tArray = new int[m_nWndHeight]; 
  745. int i,j;
  746. for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0;
  747. for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
  748. for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++)
  749. if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0)
  750. tArray[i] ++;
  751. CList<CPoint,CPoint&> myListA(sizeof(CPoint));
  752. CList<CPoint,CPoint&> myListB(sizeof(CPoint));
  753. int flag = 0;
  754. CPoint tPoint(-1,-1);
  755. for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
  756. {
  757. if(tArray[i] > 0 && flag ==0)
  758. {
  759. tPoint.x = i;
  760. flag = 1;
  761. }
  762. if(tArray[i] == 0 && flag ==1)
  763. {
  764. tPoint.y = i;
  765. myListA.AddTail(tPoint);
  766. flag = 0;
  767. }
  768. }
  769. delete tArray;
  770. //去掉长度太小的候选者
  771. for(i=0; i<myListA.GetCount();i++)
  772. {
  773. CPoint temp(-1,-1);
  774. temp = myListA.GetAt(myListA.FindIndex(i));
  775. int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100;
  776. if((temp.x-temp.y)>=minVal)
  777. myListB.AddTail(temp);
  778. }
  779. myListA.RemoveAll();
  780. //合并相邻很紧的区域
  781. bool quit = 1;
  782. while(quit)
  783. {
  784. bool doJoin = false;
  785. for(int i=0; i<myListB.GetCount()-1;i++)
  786. {
  787. CPoint temp1(-1,-1),temp2(-1,-1);
  788. temp1 = myListB.GetAt(myListB.FindIndex(i));
  789. temp2 = myListB.GetAt(myListB.FindIndex(i+1));
  790. if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/100)
  791. {
  792. temp1.y = temp2.y;
  793. myListB.RemoveAt(myListB.FindIndex(i));
  794. myListB.RemoveAt(myListB.FindIndex(i));
  795. if(i == 0) myListB.AddHead(temp1);
  796. else     myListB.InsertAfter(myListB.FindIndex(i-1),temp1);
  797. doJoin = true;
  798. break;
  799. }
  800. }
  801. if(!doJoin) quit = 0;
  802. }
  803. if(myListB.GetCount()==0)
  804. {
  805. AfxMessageBox("无法确定左眼的位置");
  806. }
  807. else
  808. {
  809. LeftEyeAreaV = myListB.GetHead();
  810. double sumX = 0.0;
  811. double sumY = 0.0;
  812. int sum = 0;
  813. m_LeftEyeLeftCorner.x = 100000;
  814. m_LeftEyeRightCorner.x = -1;
  815. for(i=LeftEyeAreaV.x; i>= LeftEyeAreaV.y;i--)
  816. for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++)
  817. if(m_tResPixelArray[i][j].rgbGreen == 0)
  818. {
  819. if(j<m_LeftEyeLeftCorner.x)
  820. {
  821. m_LeftEyeLeftCorner.x = j;
  822. m_LeftEyeLeftCorner.y = i;
  823. }
  824. if(j>m_LeftEyeRightCorner.x)
  825. {
  826. m_LeftEyeRightCorner.x = j;
  827. m_LeftEyeRightCorner.y = i;
  828. }
  829. sumX += j;
  830. sumY += i;
  831. sum++;
  832. }
  833. m_LeftEye.x = (int)(sumX/sum);
  834. m_LeftEye.y = (int)(sumY/sum);
  835. m_bLeftEyeOK = TRUE;
  836. m_bLeftEyeLeftCornerOK = TRUE;
  837. m_bLeftEyeRightCornerOK =TRUE;
  838. }
  839. myListB.RemoveAll();
  840. }
  841. //右眼
  842. if(RightEyeAreaH != CPoint(-1,-1))
  843. {
  844. int *tArray = new int[m_nWndHeight]; 
  845. int i,j;
  846. for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0;
  847. for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
  848. for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++)
  849. if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0)
  850. tArray[i] ++;
  851. CList<CPoint,CPoint&> myListA(sizeof(CPoint));
  852. CList<CPoint,CPoint&> myListB(sizeof(CPoint));
  853. int flag = 0;
  854. CPoint tPoint(-1,-1);
  855. for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--)
  856. {
  857. if(tArray[i] > 0 && flag ==0)
  858. {
  859. tPoint.x = i;
  860. flag = 1;
  861. }
  862. if(tArray[i] == 0 && flag ==1)
  863. {
  864. tPoint.y = i;
  865. myListA.AddTail(tPoint);
  866. flag = 0;
  867. }
  868. }
  869. delete tArray;
  870. //去掉长度太小的候选者
  871. for(i=0; i<myListA.GetCount();i++)
  872. {
  873. CPoint temp(-1,-1);
  874. temp = myListA.GetAt(myListA.FindIndex(i));
  875. int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100;
  876. if((temp.x-temp.y)>=minVal)
  877. myListB.AddTail(temp);
  878. }
  879. myListA.RemoveAll();
  880. //合并相邻很紧的区域
  881. bool quit = 1;
  882. while(quit)
  883. {
  884. bool doJoin = false;
  885. for(int i=0; i<myListB.GetCount()-1;i++)
  886. {
  887. CPoint temp1(-1,-1),temp2(-1,-1);
  888. temp1 = myListB.GetAt(myListB.FindIndex(i));
  889. temp2 = myListB.GetAt(myListB.FindIndex(i+1));
  890. if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/50)
  891. {
  892. temp1.y = temp2.y;
  893. myListB.RemoveAt(myListB.FindIndex(i));
  894. myListB.RemoveAt(myListB.FindIndex(i));
  895. if(i == 0) myListB.AddHead(temp1);
  896. else     myListB.InsertAfter(myListB.FindIndex(i-1),temp1);
  897. doJoin = true;
  898. break;
  899. }
  900. }
  901. if(!doJoin) quit = 0;
  902. }
  903. if(myListB.GetCount()==0)
  904. {
  905. AfxMessageBox("无法确定右眼的位置");
  906. }
  907. else
  908. {
  909. if(myListB.GetCount()==1)
  910. RightEyeAreaV = myListB.GetHead();
  911. else
  912. {
  913. CPoint tt =  myListB.GetHead();
  914. int index = myListB.GetCount();
  915. while(tt.y > LeftEyeAreaV.x && index > 0)
  916. {
  917. index --;
  918. tt = myListB.GetAt(myListB.FindIndex(myListB.GetCount()-index)); 
  919. }
  920. RightEyeAreaV = tt;
  921. }
  922. double sumX = 0.0;
  923. double sumY = 0.0;
  924. int sum = 0;
  925. m_RightEyeLeftCorner.x = 100000;
  926. m_RightEyeRightCorner.x = -1;
  927. for(i=RightEyeAreaV.x; i>=RightEyeAreaV.y;i--)
  928. for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++)
  929. if(m_tResPixelArray[i][j].rgbGreen == 0)
  930. {
  931. if(j<m_RightEyeLeftCorner.x)
  932. {
  933. m_RightEyeLeftCorner.x = j;
  934. m_RightEyeLeftCorner.y = i;
  935. }
  936. if(j>m_RightEyeRightCorner.x)
  937. {
  938. m_RightEyeRightCorner.x = j;
  939. m_RightEyeRightCorner.y = i;
  940. }
  941. sumX += j;
  942. sumY += i;
  943. sum++;
  944. }
  945. m_RightEye.x = (int)(sumX/sum);
  946. m_RightEye.y = (int)(sumY/sum);
  947. m_bRightEyeOK = TRUE;
  948. m_bRightEyeLeftCornerOK = TRUE;
  949. m_bRightEyeRightCornerOK =TRUE;
  950. }
  951. myListB.RemoveAll();
  952. }
  953. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  954. MakeBitMap();
  955. }
  956. ////////////////////////////////////////////////////////////////////////////////
  957. // 第一种方法标记脸部区域
  958. ////////////////////////////////////////////////////////////////////////////////
  959. void CFaceDetectDlg::OnBtnMarkFace1() 
  960. {
  961. if(!method1->m_bBinaryReady)
  962. {
  963. AfxMessageBox("请先计算二值化图!");
  964. return;
  965. }
  966. m_bShowFace = true;
  967. SetCursor(LoadCursor(NULL,IDC_WAIT));
  968. int *temp = new int[m_nWndWidth];
  969. int max = 0;
  970. int pos = -1;
  971. for(int j=0; j<m_nWndWidth;  j++)
  972. {
  973. int count = 0;
  974. for(int i=0; i<m_nWndHeight; i++)
  975. {
  976. if(method1->m_pBinaryArray[i][j] == 1) count++;
  977. }
  978. temp[j] = count;
  979. if(count > max)
  980. {
  981. max = count;
  982. pos = j;
  983. }
  984. }
  985. int left,right,l,top,bottom;
  986. for(l=pos; l>=0; l--)
  987. {
  988. if(temp[l]<max*0.2||l==0)
  989. {
  990. left = l;
  991. break;
  992. }
  993. }
  994. for(l=pos; l<m_nWndWidth; l++)
  995. {
  996. if(temp[l]<max*0.3||l==m_nWndWidth-1)
  997. {
  998. right = l;
  999. break;
  1000. }
  1001. }
  1002. for(int i=0; i<m_nWndHeight; i++)
  1003. {
  1004. int count = 0;
  1005. for(l = left;l<=right;l++)
  1006. {
  1007. if(method1->m_pBinaryArray[i][l] == 1) count++;
  1008. }
  1009. if(count>=(right-left)*0.5)
  1010. {
  1011. top = i;
  1012. break;
  1013. }
  1014. }
  1015. bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5);
  1016. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1017. for(i=top;i<=bottom;i++)
  1018. {
  1019. m_tResPixelArray[i][left].rgbBlue=255;
  1020. m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0;
  1021. m_tResPixelArray[i][right].rgbBlue=255;
  1022. m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0;
  1023. }
  1024. for(j=left;j<=right;j++)
  1025. {
  1026. m_tResPixelArray[top][j].rgbBlue=255;
  1027. m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0;
  1028. m_tResPixelArray[bottom][j].rgbBlue=255;
  1029. m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0;
  1030. }
  1031. MakeBitMap();
  1032. SetCursor(LoadCursor(NULL,IDC_ARROW));
  1033. if(m_bFaceOK)
  1034. {
  1035. ReplaceDlg dlg;
  1036. if(dlg.DoModal()==IDOK)
  1037. {
  1038. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1039. CRect rect(left,top,right,bottom);
  1040. m_rFaceRegion = rect;
  1041. MakeBitMap();
  1042. }
  1043. }
  1044. else
  1045. {
  1046. m_bFaceOK = true;
  1047. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1048. CRect rect(left,top,right,bottom);
  1049. m_rFaceRegion = rect;
  1050. MakeBitMap();
  1051. }
  1052. }
  1053. ////////////////////////////////////////////////////////////////////////////////
  1054. // 第二种方法标记脸部区域
  1055. ////////////////////////////////////////////////////////////////////////////////
  1056. void CFaceDetectDlg::OnBtnMarkFace2() 
  1057. {
  1058. if(!method2->m_bBinaryOK)
  1059. {
  1060. AfxMessageBox("请先计算二值化图");
  1061. return;
  1062. }
  1063. m_bShowFace = true;
  1064. SetCursor(LoadCursor(NULL,IDC_WAIT));
  1065. int *numR,*numB, i, j, left,right,top,bottom;
  1066. int maxnumR = 0, maxnumB = 0;
  1067. numR = new int[m_nWndWidth];
  1068. numB = new int[m_nWndWidth];
  1069. for(j=0;j<m_nWndWidth ;j++)
  1070. {
  1071. int countR = 0, countB = 0;
  1072. for(i=0;i<m_nWndHeight;i++)
  1073. {
  1074. if(method2->m_pBinaryArray[i][j] == 0)
  1075. countR++;
  1076. if(method2->m_pBinaryArray[i][j] == 1)
  1077. countB++;
  1078. }
  1079. if(countR > maxnumR) maxnumR = countR;
  1080. numR[j] = countR;
  1081. if(countB > maxnumB) maxnumB = countB;
  1082. numB[j] = countB;
  1083. }
  1084. CList<CPoint,CPoint> myListR(sizeof(CPoint));
  1085. CList<CPoint,CPoint> myListB(sizeof(CPoint));
  1086. CPoint tempR,tempB;
  1087. int flagR = 0,flagB = 0;
  1088. for(j=0;j<m_nWndWidth ;j++)
  1089. {
  1090. if(flagR == 0)
  1091. {
  1092. if(numR[j]>maxnumR/2)
  1093. {
  1094. flagR = 1;
  1095. tempR.x = j;
  1096. }
  1097. }
  1098. else
  1099. {
  1100. if(numR[j]<=maxnumR/2 || j==m_nWndWidth-1)
  1101. {
  1102. flagR = 0;
  1103. tempR.y = j;
  1104. myListR.AddTail(tempR);
  1105. }
  1106. }
  1107. if(flagB == 0)
  1108. {
  1109. if(numB[j]>maxnumB/5)
  1110. {
  1111. flagB = 1;
  1112. tempB.x = j;
  1113. }
  1114. }
  1115. else
  1116. {
  1117. if(numB[j]<=maxnumB/5 || j==m_nWndWidth-1)
  1118. {
  1119. flagB = 0;
  1120. tempB.y = j;
  1121. if(myListB.GetCount() > 1 && (tempB.x-myListB.GetTail().y)<20)
  1122. myListB.SetAt(myListB.GetTailPosition(),CPoint(myListB.GetTail().x,j));
  1123. else
  1124. myListB.AddTail(tempB);
  1125. }
  1126. }
  1127. }
  1128. if(numR!=NULL)delete numR;
  1129. if(numB!=NULL)delete numB;
  1130. int *hairmark, k;
  1131. hairmark = new int[m_nWndWidth];
  1132. for(j=0;j<m_nWndWidth ;j++) hairmark[j]=0;
  1133. for(k=0;k<myListB.GetCount();k++)
  1134. {
  1135. CPoint temp = myListB.GetAt(myListB.FindIndex(k));
  1136. if((temp.y-temp.x)>m_nWndWidth/10)
  1137. {
  1138. for(int t = temp.x;t<=temp.y;t++)
  1139. hairmark[t] = 1;
  1140. }
  1141. }
  1142. for(k=0;k<myListR.GetCount();k++)
  1143. {
  1144. CPoint temp = myListR.GetAt(myListR.FindIndex(k));
  1145. int templeft=-1;
  1146. int tempright=-1;
  1147. if((temp.y-temp.x)>m_nWndWidth/10)
  1148. {
  1149. for(int t=temp.x;t<=temp.y;t++)
  1150. {
  1151. if(hairmark[t]==1)
  1152. {
  1153. int endpos=t+(temp.y-temp.x)/5;
  1154. if(endpos > temp.y)endpos = temp.y;
  1155. int yes = 1;
  1156. for(int q=t;q<=endpos;q++)
  1157. if(hairmark[q]==0) yes = 0;
  1158. if(yes == 1)
  1159. {
  1160. templeft = t;
  1161. break;
  1162. }
  1163. }
  1164. }
  1165. for(int p=temp.y;p>=temp.x;p--)
  1166. {
  1167. if(hairmark[p]==1)
  1168. {
  1169. int beginpos=p-(temp.y-temp.x)/5;
  1170. if(beginpos < temp.x)beginpos = temp.x;
  1171. int yes = 1;
  1172. for(int q=p;q>=beginpos;q--)
  1173. if(hairmark[q]==0) yes = 0;
  1174. if(yes == 1)
  1175. {
  1176. tempright = p;
  1177. break;
  1178. }
  1179. }
  1180. }
  1181. }
  1182. if(templeft!=-1 && tempright!=-1)
  1183. {
  1184. left = templeft;
  1185. right = tempright;
  1186. break;
  1187. }
  1188. }
  1189. if(hairmark !=NULL) delete hairmark;
  1190. myListR.RemoveAll();
  1191. myListB.RemoveAll();
  1192. if(left-m_nWndWidth/50>0) left-=(int)m_nWndWidth/50;
  1193. else left = 0;
  1194. if(right+m_nWndWidth/40>m_nWndWidth) right=m_nWndWidth-1;
  1195. else right += m_nWndWidth/40;
  1196. for(i=0; i<m_nWndHeight; i++)
  1197. {
  1198. int count = 0;
  1199. for(int l = left;l<=right;l++)
  1200. {
  1201. if(method2->m_pBinaryArray[i][l] == 0) count++;
  1202. }
  1203. if(count>=(right-left)*0.5)
  1204. {
  1205. top = i;
  1206. break;
  1207. }
  1208. }
  1209. bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5);
  1210. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1211. for(i=top;i<=bottom;i++)
  1212. {
  1213. m_tResPixelArray[i][left].rgbBlue=255;
  1214. m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0;
  1215. m_tResPixelArray[i][right].rgbBlue=255;
  1216. m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0;
  1217. }
  1218. for(j=left;j<=right;j++)
  1219. {
  1220. m_tResPixelArray[top][j].rgbBlue=255;
  1221. m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0;
  1222. m_tResPixelArray[bottom][j].rgbBlue=255;
  1223. m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0;
  1224. }
  1225. MakeBitMap();
  1226. SetCursor(LoadCursor(NULL,IDC_ARROW));
  1227. if(m_bFaceOK)
  1228. {
  1229. ReplaceDlg dlg;
  1230. if(dlg.DoModal()==IDOK)
  1231. {
  1232. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1233. CRect rect(left,top,right,bottom);
  1234. m_rFaceRegion = rect;
  1235. MakeBitMap();
  1236. }
  1237. }
  1238. else
  1239. {
  1240. m_bFaceOK = true;
  1241. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1242. CRect rect(left,top,right,bottom);
  1243. m_rFaceRegion = rect;
  1244. MakeBitMap();
  1245. }
  1246. }
  1247. ////////////////////////////////////////////////////////////////////////////////
  1248. // 标记嘴巴
  1249. ////////////////////////////////////////////////////////////////////////////////
  1250. void CFaceDetectDlg::OnBtnMarkMouse() 
  1251. {
  1252. int i,j;
  1253. if(!(m_bLeftEyeOK&&m_bRightEyeOK))
  1254. {
  1255. AfxMessageBox("请先确定眼睛");
  1256. return;
  1257. }
  1258. //左右眼的水平区域
  1259. int nLeft,nRight,nTop,nBottom;
  1260. nLeft = m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
  1261. nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
  1262. nTop = m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
  1263. nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
  1264. SetPixelArray(m_tResPixelArray,0);
  1265. for(i=nTop; i<=nBottom; i++)
  1266. for(j=nLeft; j<=nRight; j++)
  1267. {
  1268. BYTE R,G,B;
  1269. double temp,dlta;
  1270. R = m_tOriPixelArray[i][j].rgbRed;
  1271. G = m_tOriPixelArray[i][j].rgbGreen;
  1272. B = m_tOriPixelArray[i][j].rgbBlue;
  1273. if((R==G) && (G==B)) temp = 0;
  1274. else temp = 0.5*(2*R-G-B)/sqrt((R-G)*(R-G)+(R-B)*(G-B));
  1275. dlta = acos(temp);
  1276. if(dlta < 0.2)
  1277. {
  1278. m_tResPixelArray[i][j].rgbRed = 255;  
  1279. }
  1280. else m_tResPixelArray[i][j].rgbRed = 0;
  1281. }
  1282. MakeBitMap();
  1283. AfxMessageBox("嘴的肤色鉴定");
  1284. //双目斜角
  1285. double tanThta;
  1286. if(m_RightEye.y == m_LeftEye.y) tanThta = 0;
  1287. else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x);
  1288. //双目距离
  1289. int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x);
  1290. EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y);
  1291. EyesDis = (int)sqrt(EyesDis);
  1292. //双目平均高度
  1293. int EyeV    = (m_RightEye.y + m_LeftEye.y)/2;
  1294. //可能的嘴的区域
  1295. int MouthUp   = (EyeV+1.0*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.0*EyesDis);
  1296. int MouthDown = (EyeV+1.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.5*EyesDis);
  1297. int* Y_Arry = new int[MouthDown-MouthUp];
  1298. for(i =0 ;i < MouthDown-MouthUp ;i++) Y_Arry[i] = 0;
  1299. int* X_Arry = new int[EyesDis];
  1300. for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0;
  1301. for(i = MouthUp ; i < MouthDown; i++)
  1302. for(j = m_LeftEye.x; j< m_RightEye.x; j++)
  1303. {
  1304. if(m_tResPixelArray[i][j].rgbRed == 255)
  1305. {
  1306. Y_Arry[i-MouthUp] ++;
  1307. X_Arry[j-m_LeftEye.x] ++;
  1308. }
  1309. }
  1310. int maxY = 0;
  1311. for(i =0 ;i < MouthDown-MouthUp ;i++)
  1312. {
  1313. if(Y_Arry[i]>maxY)
  1314. {
  1315. maxY = Y_Arry[i];
  1316. m_MidMouth.y =  i+MouthUp - (MouthDown-MouthUp)/10;
  1317. }
  1318. }
  1319. m_LeftMouthCorner.y  =(int)(m_MidMouth.y - tanThta*EyesDis/2);
  1320. m_RightMouthCorner.y =(int)(m_MidMouth.y + tanThta*EyesDis/2);
  1321. for(i =0 ;i < EyesDis ;i++)
  1322. {
  1323. if(X_Arry[i]>0)
  1324. {
  1325. m_LeftMouthCorner.x = i+m_LeftEye.x;
  1326. break;
  1327. }
  1328. }
  1329. for(i = EyesDis -1; i >=0 ;i--)
  1330. {
  1331. if(X_Arry[i]>0)
  1332. {
  1333. m_RightMouthCorner.x = m_LeftEye.x+i;
  1334. break;
  1335. }
  1336. }
  1337. //唇中点较薄
  1338. int min = 1000000;
  1339. for(i = (int)(3*EyesDis/7+0.5) ; i <= (int)(4*EyesDis/7+0.5);i++)
  1340. {
  1341. if(X_Arry[i]<min)
  1342. {
  1343. min = X_Arry[i];
  1344. m_MidMouth.x = m_LeftEye.x+i;
  1345. }
  1346. }
  1347. m_MidMouth.x = (int)(m_MidMouth.x+(m_LeftEye.x+EyesDis/2))/2;
  1348. m_bMidMouthOK = TRUE;
  1349. m_bLeftMouthCornerOK = TRUE;
  1350. m_bRightMouthCornerOK = TRUE;
  1351. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1352. MakeBitMap();
  1353. }
  1354. ////////////////////////////////////////////////////////////////////////////////
  1355. // 标记鼻子
  1356. ////////////////////////////////////////////////////////////////////////////////
  1357. void CFaceDetectDlg::OnBtnMarkNose() 
  1358. {
  1359. int i,j;
  1360. if(!(m_bLeftEyeOK&&m_bRightEyeOK))
  1361. {
  1362. AfxMessageBox("请先确定眼睛");
  1363. return;
  1364. }
  1365. //左右眼的水平区域
  1366. int nLeft,nRight,nTop,nBottom;
  1367. nLeft = m_rFaceRegion.left-5  > 0 ? m_rFaceRegion.left-5:0;
  1368. nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1;
  1369. nTop = m_rFaceRegion.top-5   > 0 ? m_rFaceRegion.top-5:0;
  1370. nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1;
  1371. SetPixelArray(m_tResPixelArray,0);
  1372. for(i=nTop; i<=nBottom; i++)
  1373. for(j=nLeft; j<=nRight; j++)
  1374. {
  1375. double Y;
  1376. Y = 0.30*m_tOriPixelArray[i][j].rgbRed+0.59*m_tOriPixelArray[i][j].rgbGreen
  1377. +0.11*m_tOriPixelArray[i][j].rgbBlue;
  1378. if(Y<100)
  1379. {
  1380. m_tResPixelArray[i][j].rgbRed = 255;  
  1381. }
  1382. else m_tResPixelArray[i][j].rgbRed = 0;
  1383. }
  1384. MakeBitMap();
  1385. AfxMessageBox("鼻子的肤色鉴定");
  1386. //双目斜角
  1387. double tanThta;
  1388. if(m_RightEye.y == m_LeftEye.y) tanThta = 0;
  1389. else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x);
  1390. //双目距离
  1391. int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x);
  1392. EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y);
  1393. EyesDis = (int)sqrt(EyesDis);
  1394. //双目平均高度
  1395. int EyeV    = (m_RightEye.y + m_LeftEye.y)/2;
  1396. //可能的鼻子的区域
  1397. int NoseUp   = (EyeV+0.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.5*EyesDis);
  1398. int NoseDown = (EyeV+0.8*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.8*EyesDis);
  1399. int* Y_Arry = new int[NoseDown-NoseUp];
  1400. for(i =0 ;i < NoseDown-NoseUp ;i++) Y_Arry[i] = 0;
  1401. int* X_Arry = new int[EyesDis];
  1402. for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0;
  1403. for(i = NoseUp ; i < NoseDown; i++)
  1404. for(j = m_LeftEye.x+EyesDis/5; j< m_RightEye.x-EyesDis/5; j++)
  1405. {
  1406. if(m_tResPixelArray[i][j].rgbRed == 255)
  1407. {
  1408. Y_Arry[i-NoseUp] ++;
  1409. X_Arry[j-m_LeftEye.x] ++;
  1410. }
  1411. }
  1412. int maxY = 0;
  1413. for(i =0 ;i < NoseDown-NoseUp ;i++)
  1414. {
  1415. if(Y_Arry[i]>maxY)
  1416. {
  1417. maxY = Y_Arry[i];
  1418. m_MidNose.y =  i+NoseUp;
  1419. }
  1420. }
  1421. m_LeftNostril.y  =(int)(m_MidNose.y - tanThta*EyesDis/2);
  1422. m_RightNostril.y =(int)(m_MidNose.y + tanThta*EyesDis/2);
  1423. for(i =0 ;i < EyesDis ;i++)
  1424. {
  1425. if(X_Arry[i]>0)
  1426. {
  1427. m_LeftNostril.x = i+m_LeftEye.x;
  1428. break;
  1429. }
  1430. }
  1431. for(i = EyesDis-1; i >=0 ;i--)
  1432. {
  1433. if(X_Arry[i]>0)
  1434. {
  1435. m_RightNostril.x = i+m_LeftEye.x;
  1436. break;
  1437. }
  1438. }
  1439. //唇中点较薄
  1440. int min = 1000000;
  1441. for(i = (int)(EyesDis/3+0.5) ; i <= (int)(2*EyesDis/3+0.5);i++)
  1442. {
  1443. if(X_Arry[i]<min)
  1444. {
  1445. min = X_Arry[i];
  1446. m_MidNose.x = m_LeftEye.x+i;
  1447. }
  1448. }
  1449. m_MidNose.x = (m_MidNose.x+(m_LeftEye.x+EyesDis/2))/2;
  1450. m_bMidNoseOK = TRUE;
  1451. m_bLeftNostrilOK = TRUE;
  1452. m_bRightNostrilOK = TRUE;
  1453. CopyBitMap(m_tResPixelArray,m_tOriPixelArray);
  1454. MakeBitMap();
  1455. }
  1456. ////////////////////////////////////////////////////////////////////////////////
  1457. // 打开文件
  1458. ////////////////////////////////////////////////////////////////////////////////
  1459. void CFaceDetectDlg::OnBtnOpenfile() 
  1460. {
  1461. CAddSampleDlg FileDlg(TRUE, "", NULL, 
  1462. OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, 
  1463. "BMP人脸图像(*.bmp)|*.bmp|所有文件(*.*)|*.*||",
  1464. AfxGetMainWnd());
  1465. CString strFile;
  1466. if (FileDlg.DoModal () != IDOK)
  1467. return;
  1468. POSITION pos = FileDlg.GetStartPosition();
  1469. strFile = FileDlg.GetNextPathName(pos);
  1470. m_pMainDib->Open(strFile);
  1471. m_nWndWidth = m_pMainDib->GetWidth();
  1472. m_nWndHeight= m_pMainDib->GetHeight();
  1473. m_sFileName = strFile;
  1474. m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0;
  1475. m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK =
  1476. m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = 
  1477. m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false;
  1478. m_bMidMouthOK = m_bMidNoseOK = false;
  1479. m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = 
  1480. m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner =
  1481. m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1);
  1482. SetCursor(LoadCursor(NULL,IDC_WAIT));
  1483. //获取像素的值
  1484. LoadOriPixel(m_pMainDib);
  1485. MakeBitMap();
  1486. SetCursor(LoadCursor(NULL,IDC_ARROW));
  1487. }
  1488. ////////////////////////////////////////////////////////////////////////////////
  1489. // 画图
  1490. ////////////////////////////////////////////////////////////////////////////////
  1491. void CFaceDetectDlg::MyDraw()
  1492. {
  1493. CRect rc;
  1494. pDCShow->GetWindow()->GetClientRect(&rc);
  1495. pDCShow->Rectangle(&rc);
  1496. CDC dc;
  1497. CBitmap *pOldBitmap;
  1498. dc.CreateCompatibleDC(pDCShow);
  1499. pOldBitmap=dc.SelectObject(m_pResMap);
  1500. pDCShow->StretchBlt(0,0,m_nWndWidth,m_nWndHeight,&dc,0,0,m_nWndWidth,m_nWndHeight,SRCCOPY);
  1501. dc.SelectObject(pOldBitmap);
  1502. dc.DeleteDC();
  1503. }