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