You are on page 1of 9

Face Detection using OpenCV

ALAMAT: http://opencv.willowgarage.com/wiki/FaceDetection Note: This tutorial uses the OpenCV 1 interface and (as far as I can tell) is not compatible with the version of haarcascade_frontalface_alt.xml included in the OpenCV 2 code source. See http://opencv.itseez.com/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.html for the OpenCV 2 version of the tutorial which is compatible with the current XML files. • How to compile and run the facedetect.c is one of the frequently asked question in the OpenCV Yahoo! Groups. I'll try to explain it to my best. Feel free to edit it if you have some more details.. Haar Like Features:What is that? A recognition process can be much more efficient if it is based on the detection of features that encode some information about the class to be detected. This is the case of Haar-like features that encode the existence of oriented contrasts between regions in the image. A set of these features can be used to encode the contrasts exhibited by a human face and their spacial relationships. Haar-like features are so called because they are computed similar to the coefficients in Haar wavelet transforms. The object detector of OpenCV has been initially proposed by Paul Viola and improved by Rainer Lienhart. First, a classifier (namely a cascade of boosted classifiers working with haar-like features) is trained with a few hundreds of sample views of a particular object (i.e., a face or a car), called positive examples, that are scaled to the same size (say, 20x20), and negative examples - arbitrary images of the same size. After a classifier is trained, it can be applied to a region of interest (of the same size as used during the training) in an input image. The classifier outputs a "1" if the region is likely to show the object (i.e., face/car), and "0" otherwise. To search for the object in the whole image one can move the search window across the image and check every location using the classifier. The classifier is designed so that it can be easily "resized" in order to be able to find the objects of interest at different sizes, which is more efficient than resizing the image itself. So, to find an object of an unknown size in the image the scan procedure should be done several times at different scales. The word "cascade" in the classifier name means that the resultant classifier consists of several simpler classifiers (stages) that are applied subsequently to a region of interest until at some stage the candidate is rejected or all the stages are passed. The word "boosted" means that the classifiers at every stage of the cascade are complex themselves and they are built out of basic classifiers using one of four different boosting techniques (weighted voting). Currently Discrete Adaboost, Real Adaboost, Gentle Adaboost and Logitboost are supported. The basic classifiers are decision-tree classifiers with at least 2 leaves. Haar-like features are the input to the basic classifers.The feature used in a particular classifier is specified by its shape , position within the region of interest and the scale (this scale is not the same as the scale used at the detection stage, though these two scales are multiplied). Ok. Enough of the theory part. Now to the coding part: (This code might have a memory leak. Scroll down to the bottom of the page for information on how to fix it.) Here is my commented facedetect.c file:

h> <time.c // Include header files #include "cv. int main( int argc. // Used for calculations int optlen = strlen("--cascade="). // Create a string that contains the cascade name const char* cascade_name = "haarcascade_frontalface_alt.h> <limits. input_name = argc > 2 ? argv[2] : 0. // Create a new Haar classifier static CvHaarClassifierCascade* cascade = 0. "--cascade=".*/ // Main function.h" #include "highgui. // Images to capture the frame from video or camera or from file IplImage *frame. const char* input_name.h" #include #include #include #include #include #include #include #include #include <stdio. } else { .h> <stdlib. char** argv ) { // Structure for getting video from camera or avi CvCapture* capture = 0. optlen ) == 0 ) { cascade_name = argv[1] + optlen. // Function prototype for detecting and drawing an object from an image void detect_and_draw( IplImage* image ).h> // Create memory for calculations static CvMemStorage* storage = 0.h> <ctype. /* "haarcascade_profileface. // Check for the correct usage of the command line if( argc > 1 && strncmp( argv[1].h> <assert. *frame_copy = 0.h> <float.xml". // Input file name for avi or image file.h> <string.xml".h> <math. defines the entry point for the program.====================' // OpenCV Sample Application: facedetect.

. // Check the origin of image. /*input_name = argc > 1 ? argv[1] : 0. } // Allocate the memory storage storage = cvCreateMemStorage(0). // Allocate framecopy as the same size of the frame if( !frame_copy ) frame_copy = cvCreateImage( cvSize(frame->width. // Find if the capture is loaded successfully or not.frame->height). // Create a new named window with title: result cvNamedWindow( "result". frame_copy. frame = cvRetrieveFrame( capture ).fprintf( stderr. for(. 0. copy the image frame to if( frame->origin == IPL_ORIGIN_TL ) cvCopy( frame. If top left. if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') ) capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] .'0' ). 0 ). 0. 0 ). return -1. frame_copy. IPL_DEPTH_8U.) { // Capture the frame and load it in IplImage if( !cvGrabFrame( capture )) break. // If the frame does not exist. // Check whether the cascade has loaded successfully.*/ } // Load the HaarClassifierCascade cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name. frame->nChannels ). quit the loop if( !frame ) break. "Usage: facedetect --cascade=\"<cascade_path>\" [filename| camera_index]\n" ). // If loaded succesfully. then: if( capture ) { // Capture from the camera. return -1. // Else flip and copy the image . Else report and error and quit if( !cascade ) { fprintf( stderr. "ERROR: Could not load classifier cascade\n" ). // Find whether to detect the object from file or from camera. 1 ). else capture = cvCaptureFromAVI( input_name ).

1 ). then: if( image ) { // Detect and draw the face detect_and_draw( image ).jpg". while( len > 0 && isspace(buf[len-1]) ) len--. or the input_name specified const char* filename = input_name ? input_name : (char*)"lena. f ) ) { // Remove the spaces if any. // Release the image memory cvReleaseImage( &image ). // Wait for a while before proceeding to the next frame if( cvWaitKey( 10 ) >= 0 ) break. // Wait for user input cvWaitKey(0). and clean up the name int len = (int)strlen(buf). then: else { // Assume the image to be lena. buf[len] = '\0'. and capture memory cvReleaseImage( &frame_copy ). } else { /* assume it is a text file containing the list of the image filenames to be processed . // Call the function to detect and draw the face detect_and_draw( frame_copy ). } // Release the images.else cvFlip( frame. . // Get the line from the file while( fgets( buf. if( f ) { char buf[1000+1]. // Load the image from that filename IplImage* image = cvLoadImage( filename. // If Image is loaded succesfully. 1000. frame_copy. 0 ). cvReleaseCapture( &capture ).one per line */ FILE* f = fopen( filename. } // If the capture is not loaded succesfully. "rt" ).jpg.

// Wait for the user input. 1 ). and release the memory cvWaitKey(0).img->height/scale). cascade. storage.1. i++ ) . // Find whether the cascade is loaded. cvReleaseImage( &image ). then: if( cascade ) { // There can be more than one face in an image. for( i = 0. // Clear the memory storage which was used before cvClearMemStorage( storage ). // Create two points to represent the face locations CvPoint pt1. int i. to find the faces. CV_HAAR_DO_CANNY_PRUNING. cvSize(40. // return 0 to indicate successfull execution of the program return 0. // Loop the number of faces found. // Destroy the window previously created with filename: "result" cvDestroyWindow("result"). 40) ).// Load the image from the filename present in the buffer image = cvLoadImage( buf. } } } } } // Close the file fclose(f). 1. 8. 3 ). // If the image was loaded succesfully. So create a growable sequence of faces. i < (faces ? faces->total : 0). // Detect the objects and store them in the sequence CvSeq* faces = cvHaarDetectObjects( img. pt2. 2. // Create a new image based on the input image IplImage* temp = cvCreateImage( cvSize(img->width/scale. } // Function to detect and draw any faces that is present in an image void detect_and_draw( IplImage* img ) { int scale = 1. then: if( image ) { // Detect and draw the face from the image detect_and_draw( image ). If yes.

// Release the temp image created.7/samples/c/ 2 Change the permissions of build_all. If you have your own image: "face.{ // Create a new rectangle for drawing the face CvRect* r = (CvRect*)cvGetSeqElem( faces.9.xml" Now. Then. cvReleaseImage( &temp ).. // Find pt1.xml" If you are using an IDE. pt2. CV_RGB(255. 8. 3. you'll need to add the classifier location to the additional command line arguments.y = the dimensions of the face. 0 ). (r->y+r->height)*scale.. You can optionally specify the avi file or image file to the command prompt. the source code will compile and run fine. pt1. r->y*scale...xml" Now..sh . Suppose that you have installed OpenCV in its default location:C:/Program Files..and scale it if necessary r->x*scale. } =======================' Hope you understood what the code meant.. you can run the facedetect sample with this command in the prompt: facedetect --cascade="C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt. You should verify that the filehaarcascade_frontalface_alt. i ).jpg ….. It is normally present in the/OpenCV/data/haarcascadeslocation. (r->x+r->width)*scale.jpg"..x = pt1... you can go toProject->Debugging>Command Arguments In Additional Options tab.xmlis present inside the folder or not.y = pt2.xml" face.x = pt2. then you can add that to the command line like this: --cascade="C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.sh file: chmod 777 build_all.0. after specifying the classifier.. the exact location of the classifier is:"C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt. // Show the image in the window named "result" cvShowImage( "result". For example. } } // Draw the rectangle in the input image cvRectangle( img.. and want to play with the source code.0). enter this:--cascade="C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.' On Linux 1 Go to the directory: opencv-0..????????. In Visual C++.. img ). you have to specify the exact location of the haar classifier xml file. How to run this code? As said in the code...

sh file: ..h> <string.*/ // Function prototype for detecting and drawing an object from an image void detect_and_draw( IplImage* image ). int main( int argc. ..h> <limits. // Wait for user input before quitting the program cvWaitKey()./facedetect --cascade="/home/bob/opencv0./build_all.h" #include #include #include #include #include #include #include #include #include <stdio.xml". // Main function.9. char** argv ) { // Create a sample image IplImage *img = cvLoadImage("face. Thats it.h> <assert. // Include header files #include "cv.h> <time.7/data/haarcascades/haarcascade_frontalface_alt.h> // Create a string that contains the exact cascade name const char* cascade_name = "C:/Program Files/OpenCV/data/haarcascades/haarcascade_frontalface_alt.h" #include "highgui. // Release the image cvReleaseImage(&img).jpg //////////////////////// What if you want to add this as a part of your source code? Pass your image to the detect_and_draw function .h> <math. /* "haarcascade_profileface.h> <stdlib. // Call the function to detect and draw the face positions detect_and_draw(img).xml" • (make sure you specify the exact path of an xml file!!!) 5 To run with a parameter: .xml". Here is a sample code: // Sample Application to demonstrate how Face detection can be done as a part of your source code.h> <ctype..xml" baboon./facedetect --cascade="/home/bob/opencv0. defines the entry point for the program.jpg").h> <float.7/data/haarcascades/haarcascade_frontalface_alt.sh 4 Run facedetect: .3 Run the build_all.9.

1. 1 ). 0. 0 ). CV_HAAR_DO_CANNY_PRUNING. // Create a new Haar classifier static CvHaarClassifierCascade* cascade = 0. "ERROR: Could not load classifier cascade\n" ). cascade. So create a growable sequence of faces. ). to find the faces. int i. Else report and error and quit if( !cascade ) { fprintf( stderr. 0. } // Allocate the memory storage storage = cvCreateMemStorage(0). pt2. int scale = 1. // Check whether the cascade has loaded successfully. // return 0 to indicate successfull execution of the program return 0.1. // Find whether the cascade is loaded. // Create a new image based on the input image IplImage* temp = cvCreateImage( cvSize(img->width/scale. } // Function to detect and draw any faces that is present in an image void detect_and_draw( IplImage* img ) { // Create memory for calculations static CvMemStorage* storage = 0.// Destroy the window previously created with filename: "result" cvDestroyWindow("result"). 3 // Create two points to represent the face locations CvPoint pt1. return. 8. If yes. // Clear the memory storage which was used before cvClearMemStorage( storage ). storage. // Load the HaarClassifierCascade cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name. then: if( cascade ) { // There can be more than one face in an image. 2. // Detect the objects and store them in the sequence CvSeq* faces = cvHaarDetectObjects( img.img->height/scale). // Create a new named window with title: result cvNamedWindow( "result". .

} } // Draw the rectangle in the input image cvRectangle( img. (r->y+r->height)*scale. pt1. } ///////////////////// .y = the dimensions of the face. for( i = 0.0. // Release the temp image created. cvReleaseImage( &temp ).0). 8. CV_RGB(255. 0 ). // Loop the number of faces found. // Show the image in the window named "result" cvShowImage( "result". r->y*scale.x = pt2. img ).x = pt1.cvSize(40. pt2. i < (faces ? faces->total : 0). // Find pt1.and scale it if necessary r->x*scale. 40) ). 3. i ). (r->x+r->width)*scale.y = pt2. i++ ) { // Create a new rectangle for drawing the face CvRect* r = (CvRect*)cvGetSeqElem( faces.