|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionEyes are the most important features of the human face. So effective usage of eye movements as a communication technique in user-to-computer interfaces can find place in various application areas. Eye tracking and the information provided by the eye features have the potential to become an interesting way of communicating with a computer in a human-computer interaction (HCI) system. So with this motivation, designing a real-time eye feature tracking software is the aim of this project. The purpose of the project is to implement a real-time eye-feature tracker with the following capabilities:
Instructions to Run and Rebuild TrackEyeInstallation Instructions
Settings to be Done to Perform a Good TrackingSettings for Face & Eye DetectionUnder TrackEye Menu --> Tracker Settings
Settings for Pupil DetectionCheck “Track eyes in details” and then check “Detect also eye pupils”. Click “Adjust Parameters” button:
Settings for SnakeCheck “Indicate eye boundary using active snakes”. Click “Settings for snake” button:
BackgroundSo far there has been a lot of work on eye detection and before the project, the previous methods were carefully studied to determine the implemented method. We can classify studies related to eye into two main categories as listed below: Special Equipment Based ApproachesThese type of studies use the necessary equipment which will give a signal of some sort which is proportional to the position of the eye in the orbit. Various methods that are current in use are Electrooculography, Infra-Red Oculography, Scleral search coils. These methods are completely out of our project. Image Based ApproachesImage based approaches perform eye detections on the images. Most of the image based methods try to detect the eyes using the features of the eyes. Methods used so far are knowledge-based methods, feature-based methods (color, gradient), simple template matching, appearance methods. Another interesting method is “Deformable template matching” which is based on matching a geometrical eye template on an eye image by minimizing the energy of the geometrical model. Implementation of TrackEyeThe implemented project is on three components:
Face DetectionTwo different methods were implemented in the project. They are:
Continuously Adaptive Mean-Shift AlgorithmAdaptive Mean Shift algorithm is used for tracking human faces and is based on robust non-parametric technique for climbing density gradients to find the mode (peak) of probability distributions called the mean shift algorithm. As faces are tracked in video sequences, mean shift algorithm is modified to deal with the problem of dynamically changing color probability distributions. The block diagram of the algorithm is given below:
Haar-Face Detection MethodThe second face detection algorithm is based on a classifier working with Haar-Like features (namely a cascade of boosted classifiers working with Haar-like features). First of all it is trained with a few hundreds of sample views of a face. After a classifier is trained, it can be applied to a region of interest in an input image. The classifier outputs a " Eye DetectionTwo different methods were implemented in the project:
Template-MatchingTemplate-Matching is a well-known method for object detection. In our template matching method, a standard eye pattern is created manually and given an input image, the correlation values with the standard patterns are computed for the eyes. The existence of an eye is determined based on the correlation values. This approach has the advantage of being simple to implement. However, it may sometimes be inadequate for eye detection since it cannot effectively deal with variation in scale, pose and shape. Adaptive EigenEye MethodAdaptive OpenCV Functions for Object Tracking and Detection
Sample Code for Haar-Face Trackingvoid CTrackEyeDlg::HaarFaceDetect( IplImage* img, CvBox2D* faceBox)
{
int scale = 2;
IplImage* temp = cvCreateImage( cvSize(img->width/2,img->height/2), 8, 3 );
CvPoint pt1, pt2;
int i;
cvPyrDown( img, 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 );
NumOfHaarFaces = faces->total;
if (NumOfHaarFaces > 0)
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, 0, 0 );
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
#ifdef WIN32
pt1.y = img->height - r->y*scale;
pt2.y = img->height - (r->y+r->height)*scale;
#else
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
#endif
faceBox->center.x = (float)(pt1.x+pt2.x)/2.0;
faceBox->center.y = (float)(pt1.y+pt2.y)/2;
faceBox->size.width = (float)(pt2.x - pt1.x);
faceBox->size.height = (float)(pt1.y - pt2.y);
}
}
cvShowImage( "Tracking", img );
cvReleaseImage( &temp );
}
Sample Code for CamShift Algorithm// Inputs for CamShift algorithm
IplImage* HUE = cvCreateImage(cvGetSize(SampleForHUE), IPL_DEPTH_8U, 1);
extractHUE(SampleForHUE, HUE); // ** Extract HUE information
int hist_size = 20;
float ranges[] = { 0, 180 };
float* pranges[] = {ranges};
hist = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, pranges, 1 );
cvCalcHist(&HUE, hist); // Calculate histogram of HUE part
hueFrame = cvCreateImage(cvGetSize(CameraFrame), IPL_DEPTH_8U, 1);
backProject = cvCreateImage(cvGetSize(CameraFrame), IPL_DEPTH_8U, 1);
extractHUE(CameraFrame, hueFrame);
while (trackControl != 0)
{
extractHUE( CameraFrame, hueFrame );
cvCalcBackProject( &hueFrame, backProject, hist ); // Probability is formed
//cvShowImage("Tester2", backProject);
cvCamShift( backProject, searchWin, cvTermCriteria( CV_TERMCRIT_EPS |
CV_TERMCRIT_ITER, 15, 0.1 ), &comp, &faceBox );
searchWin = comp.rect;
}
Sample Code Template Matching// Template Matching for Eye detection
void Face::findEyes_TM(IplImage* faceImage, TrackingSettings* settings)
{
CvSize faceSize; faceSize = cvGetSize(faceImage);
// Load Template from the eye database
CString fileName;
// Name of the template for left eye
fileName.Format("%s\\eye%d.jpg", settings->params->DBdirectory, 0);
IplImage* eyeImage_Left = cvLoadImage(fileName, -1);
// Name of the template for left eye
fileName.Format("%s\\eye%d.jpg", settings->params->DBdirectory, 1);
IplImage* eyeImage_Right = cvLoadImage(fileName, -1);
IplImage* tempTemplateImg_Left; IplImage* tempTemplateImg_Right;
IplImage* templateImg_Left; IplImage* templateImg_Right;
if (eyeImage_Left == NULL || eyeImage_Right == NULL)
{
MessageBox(NULL, "Templates can not be loaded.\n
Please check your eye database folder", "Error", MB_OK||MB_ICONSTOP);
exit(1);
}
else
{
// Change color space according to the settings entered by the user
tempTemplateImg_Left = cvCreateImage(cvGetSize(eyeImage_Left), IPL_DEPTH_8U, 1);
changeColorSpace(settings, eyeImage_Left, tempTemplateImg_Left);
tempTemplateImg_Right =
cvCreateImage(cvGetSize(eyeImage_Right), IPL_DEPTH_8U, 1);
changeColorSpace(settings, eyeImage_Right, tempTemplateImg_Right);
float idealWidth = faceSize.width * settings->params->ratio;
float conversionRatio = idealWidth/(float)tempTemplateImg_Left->width;
CvSize newSize;
newSize.width = (int)idealWidth;
newSize.height = (int)(tempTemplateImg_Left->height*conversionRatio);
templateImg_Left = cvCreateImage(newSize, IPL_DEPTH_8U, 1);
cvResize(tempTemplateImg_Left, templateImg_Left, CV_INTER_LINEAR); // was NN
cvReleaseImage(&eyeImage_Left);
cvReleaseImage(&tempTemplateImg_Left);
templateImg_Right = cvCreateImage(newSize, IPL_DEPTH_8U, 1);
cvResize(tempTemplateImg_Right, templateImg_Right, CV_INTER_LINEAR); // was NN
cvReleaseImage(&eyeImage_Right);
cvReleaseImage(&tempTemplateImg_Right);
}
// *************************************************************
// ************Search faceImage for eyes************************
// *************************************************************
IplImage* GRAYfaceImage = cvCreateImage(faceSize, IPL_DEPTH_8U, 1);
changeColorSpace(settings, faceImage, GRAYfaceImage);
//cvCvtColor( faceImage, GRAYfaceImage, CV_RGB2GRAY);
//GRAYfaceImage->origin = 1;
// ** Warning at this point image origin is bottom-left corner.
// ** Eye1 search area
int x_left = 0;
int y_left = 0;
int width_left = (int)((float)(faceSize.width/2.0));
int height_left = (int)((float)(faceSize.height));
CvRect rect_Eye1 = cvRect(x_left, y_left, width_left, height_left);
CvMat* Eye1Image = cvCreateMat(width_left, height_left, CV_8UC1);
cvGetSubRect(GRAYfaceImage, Eye1Image, rect_Eye1 );
cvFlip( Eye1Image, Eye1Image, 0);
// ** Eye2 search area
int x_right= (int)((float)(faceSize.width/2.0));
int y_right = 0;
int width_right = (int)((float)(faceSize.width/2.0));
int height_right = (int)((float)(faceSize.height));
CvRect rect_Eye2 = cvRect(x_right, y_right, width_right, height_right);
CvMat* Eye2Image = cvCreateMat(width_right, height_right, CV_8UC1);
cvGetSubRect(GRAYfaceImage, Eye2Image, rect_Eye2 );
cvFlip( Eye2Image, Eye2Image, 0);
// OpenCV says that size of the result must be the following:
CvSize size;
size.height= Eye1Image->height - templateImg_Left->height + 1;
size.width = Eye1Image->width - templateImg_Left->width + 1;
IplImage* result1 = cvCreateImage( size,IPL_DEPTH_32F,1);
IplImage* result2 = cvCreateImage( size,IPL_DEPTH_32F,1);
// Left Eye
cvMatchTemplate( Eye1Image, templateImg_Left, result1, settings->params->tempMatch);
// Right Eye
cvMatchTemplate( Eye2Image, templateImg_Right, result2, settings->params->tempMatch);
// find the best match location - LEFT EYE
double minValue1, maxValue1;
CvPoint minLoc1, maxLoc1;
cvMinMaxLoc( result1, &minValue1, &maxValue1, &minLoc1, &maxLoc1 );
cvCircle( result1, maxLoc1, 5, settings->programColors.colors[2], 1 );
// transform point back to original image
maxLoc1.x += templateImg_Left->width / 2;
maxLoc1.y += templateImg_Left->height / 2;
settings->params->eye1.coords.x = maxLoc1.x;
settings->params->eye1.coords.y = maxLoc1.y;
settings->params->eye1.RectSize.width = templateImg_Left->width;
settings->params->eye1.RectSize.height = templateImg_Left->height;
settings->params->eye1.eyefound = true;
// find the best match location - RIGHT EYE
double minValue2, maxValue2;
CvPoint minLoc2, maxLoc2;
cvMinMaxLoc( result2, &minValue2, &maxValue2, &minLoc2, &maxLoc2 );
cvCircle( result2, maxLoc2, 5, settings->programColors.colors[2], 1 );
// transform point back to original image
maxLoc2.x += templateImg_Left->width / 2;
maxLoc2.y += templateImg_Left->height / 2;
settings->params->eye2.coords.x = maxLoc2.x+(int)faceSize.width/2;
settings->params->eye2.coords.y = maxLoc2.y;
settings->params->eye2.RectSize.width = templateImg_Left->width;
settings->params->eye2.RectSize.height = templateImg_Left->height;
settings->params->eye2.eyefound = true;
cvCircle( Eye1Image, maxLoc1, 5, settings->programColors.colors[2], 1 );
cvCircle( Eye2Image, maxLoc2, 5, settings->programColors.colors[2], 1 );
}
Sample Code Adaptive EigenEye Methodvoid Face::findEyes(IplImage* faceImage, TrackingSettings* settings)
{
IplImage** images = (IplImage**)malloc(sizeof(IplImage*)*numOfImages);
IplImage** eigens = (IplImage**)malloc(sizeof(IplImage*)*numOfImages);
IplImage* averageImage;
IplImage* projection;
CvSize faceSize; faceSize = cvGetSize(faceImage);
eigenSize newEigenSize;
newEigenSize.width = faceSize.width * settings->params->ratio;
newEigenSize.conversion = ((float)newEigenSize.width) / ((float)database[0]->width);
newEigenSize.height = ((float)database[0]->height) * newEigenSize.conversion;
CvSize newSize;
newSize.width = (int)newEigenSize.width;
newSize.height = (int)newEigenSize.height;
IplImage* tempImg = cvCreateImage( newSize, IPL_DEPTH_8U, 1);
// **********Initializations**********
for (int i=0; i
History
* Please note that | ||||||||||||||||||||||