在得到双眼区后,进一步搜索得到左右眼睛的中心和半径。根据得到的半径可以粗略估算眼睛的开闭状态,精确的眼睛状态可以由事先采集到的开闭眼睛模板的模板匹配系数得到。如果解决了模板更新的问题,眼睛的状态就可以稳定的获得。 int GetMassCenter(IplImage *img, CvRect rectEyes, CvBox2D32f *pBox) { assert(img != NULL && pBox != NULL); IplImage *cur, *cpy; cur = cvCreateImage(cvSize(rectEyes.width, rectEyes.height), 8, 1); cpy = cvCreateImage(cvSize(rectEyes.width, rectEyes.height), 8, 1); cvSetImageROI(img, rectEyes); cvCopy(img, cur, NULL); cvResetImageROI(img); BYTE* src = (BYTE *)cur->imageData; int i, j, s1 = 0, s2 = 0, th; for (i = 0; i < cur->width; i ++) { for (j = 0; j < cur->height / 2; j ++) { s1 += src[j * cur->width +i]; } for (j = cur->height / 2; j < cur->height; j ++) { s2 += src[j * cur->width +i]; } } th = (s1 * 3 + s2 * 7) / (cur->width * cur->height * 10) ; cvZero(cpy); cvThreshold(cur, cpy, th, 255, CV_THRESH_BINARY_INV); CvMoments mu; CvMat mat; double M00,X,Y; CvRect rt = {0, 0, rectEyes.width, rectEyes.height}; cvMoments( cvGetSubRect(cpy, &mat, rt), μ, 0 ); M00 = cvGetSpatialMoment( μ, 0, 0 ); if (M00 <= 0) { cvReleaseImage(&cpy); cvReleaseImage(&cur); return -1; } X = cvGetSpatialMoment( μ, 1, 0 )/M00; Y = cvGetSpatialMoment( μ, 0, 1 )/M00; #if 1 double a, b, c, d; a = cvGetSpatialMoment( μ, 2, 0 )/M00 - X * X; b = cvGetSpatialMoment( μ, 1, 1 )/M00 - Y * X; b *= 2; c = cvGetSpatialMoment( μ, 0, 2 )/M00 - Y * Y; d = sqrt( b * b + (a - c) * (a - c) ); pBox->center.x = rectEyes.x + X; pBox->center.y = rectEyes.y + Y; pBox->size.width = (float) 2 * sqrt((a + c + d) / (float)2); pBox->size.height= (float) 2 * sqrt((a + c - d) / (float)2); pBox->angle = - atan2(b, a - c) * ((float)180 / 3.1415926f); #else //find contours bool bBig = false; CvSeq* firstContour, *cnt, *pBiggest; CvMemStorage* storage = cvCreateMemStorage(1000); cvFindContours(cpy, storage, &firstContour, sizeof(CvContour), CV_RETR_EXTERNAL); pBiggest = firstContour; for(cnt = firstContour; cnt; cnt=cnt->h_next) { if (cnt->total > pBiggest->total) { pBiggest = cnt; } bBig = true; } if (bBig) { CvPoint *pointArray = (CvPoint*) malloc(pBiggest->total*sizeof(CvPoint)); CvPoint2D32f* pointArray32f = (CvPoint2D32f*)malloc(sizeof(CvPoint2D32f)*pBiggest->total); cvCvtSeqToArray(pBiggest, pointArray, CV_WHOLE_SEQ); for(int i=0; i<pBiggest->total; i++) { pointArray32f[i].x = (float)pointArray[i].x; pointArray32f[i].y = (float)pointArray[i].y; } if (pBiggest->total > 6) { cvFitEllipse(pointArray32f, pBiggest->total, pBox); pBox->angle = -pBox->angle; pBox->center.x += (float)rectEyes.x; pBox->center.y += (float)rectEyes.y; } else { cvReleaseImage(&cpy); cvReleaseImage(&cur); return - 1; } } cvReleaseMemStorage(&storage); #endif cvReleaseImage(&cpy); cvReleaseImage(&cur); return 0; }; #if !defined(AFX_PUPIL_DETECTOE_H_INCLUDED) #define AFX_PUPIL_DETECTOE_H_INCLUDED #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "cv.h" #include "cvUtils.h" class CPupilDetector { public: void Process(IplImage *img, CvRect rectEyes) { assert(img != NULL); int ret; CvRect roiLeft, roiRight; m_FoundLeft = false; m_foundRight= false; roiLeft = rectEyes; roiLeft.width /= 2; ret = GetMassCenter(img, roiLeft, &m_BoxLeft); if (ret == 0) { m_FoundLeft = true; m_LeftEye.x = (int)m_BoxLeft.center.x; m_LeftEye.y = (int)m_BoxLeft.center.y; } roiRight= rectEyes; roiRight.width/= 2; roiRight.x += roiRight.width; ret = GetMassCenter(img, roiRight, &m_BoxRight); if (ret == 0) { m_foundRight = true; m_RightEye.x = (int)m_BoxRight.center.x; m_RightEye.y = (int)m_BoxRight.center.y; } }; CPupilDetector() { threshold = 50; m_FoundLeft = false; m_foundRight= false; }; void SetParam(int th) { threshold = th; }; public: bool m_FoundLeft; bool m_foundRight; CvPoint m_LeftEye; CvPoint m_RightEye; CvBox2D32f m_BoxLeft; CvBox2D32f m_BoxRight; private: int threshold; }; #endif //AFX_PUPIL_DETECTOE_H_INCLUDED