Update the changelog
[opencv] / samples / c / facedetect.c
1 #include "cv.h"
2 #include "highgui.h"
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <math.h>
9 #include <float.h>
10 #include <limits.h>
11 #include <time.h>
12 #include <ctype.h>
13
14 #ifdef _EiC
15 #define WIN32
16 #endif
17
18 static CvMemStorage* storage = 0;
19 static CvHaarClassifierCascade* cascade = 0;
20 static CvHaarClassifierCascade* nested_cascade = 0;
21 int use_nested_cascade = 0;
22
23 void detect_and_draw( IplImage* image );
24
25 const char* cascade_name =
26     "../../data/haarcascades/haarcascade_frontalface_alt.xml";
27 /*    "haarcascade_profileface.xml";*/
28 const char* nested_cascade_name =
29     "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
30 //    "../../data/haarcascades/haarcascade_eye.xml";
31 double scale = 1;
32
33 int main( int argc, char** argv )
34 {
35     CvCapture* capture = 0;
36     IplImage *frame, *frame_copy = 0;
37     IplImage *image = 0;
38     const char* scale_opt = "--scale=";
39     int scale_opt_len = (int)strlen(scale_opt);
40     const char* cascade_opt = "--cascade=";
41     int cascade_opt_len = (int)strlen(cascade_opt);
42     const char* nested_cascade_opt = "--nested-cascade";
43     int nested_cascade_opt_len = (int)strlen(nested_cascade_opt);
44     int i;
45     const char* input_name = 0;
46
47     for( i = 1; i < argc; i++ )
48     {
49         if( strncmp( argv[i], cascade_opt, cascade_opt_len) == 0 )
50             cascade_name = argv[i] + cascade_opt_len;
51         else if( strncmp( argv[i], nested_cascade_opt, nested_cascade_opt_len ) == 0 )
52         {
53             if( argv[i][nested_cascade_opt_len] == '=' )
54                 nested_cascade_name = argv[i] + nested_cascade_opt_len + 1;
55             nested_cascade = (CvHaarClassifierCascade*)cvLoad( nested_cascade_name, 0, 0, 0 );
56             if( !nested_cascade )
57                 fprintf( stderr, "WARNING: Could not load classifier cascade for nested objects\n" );
58         }
59         else if( strncmp( argv[i], scale_opt, scale_opt_len ) == 0 )
60         {
61             if( !sscanf( argv[i] + scale_opt_len, "%lf", &scale ) || scale < 1 )
62                 scale = 1;
63         }
64         else if( argv[i][0] == '-' )
65         {
66             fprintf( stderr, "WARNING: Unknown option %s\n", argv[i] );
67         }
68         else
69             input_name = argv[i];
70     }
71
72     cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
73
74     if( !cascade )
75     {
76         fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
77         fprintf( stderr,
78         "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
79         "   [--nested-cascade[=\"nested_cascade_path\"]]\n"
80         "   [--scale[=<image scale>\n"
81         "   [filename|camera_index]\n" );
82         return -1;
83     }
84     storage = cvCreateMemStorage(0);
85     
86     if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') )
87         capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' );
88     else if( input_name )
89     {
90         image = cvLoadImage( input_name, 1 );
91         if( !image )
92             capture = cvCaptureFromAVI( input_name );
93     }
94     else
95         image = cvLoadImage( "lena.jpg", 1 );
96
97     cvNamedWindow( "result", 1 );
98
99     if( capture )
100     {
101         for(;;)
102         {
103             if( !cvGrabFrame( capture ))
104                 break;
105             frame = cvRetrieveFrame( capture );
106             if( !frame )
107                 break;
108             if( !frame_copy )
109                 frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
110                                             IPL_DEPTH_8U, frame->nChannels );
111             if( frame->origin == IPL_ORIGIN_TL )
112                 cvCopy( frame, frame_copy, 0 );
113             else
114                 cvFlip( frame, frame_copy, 0 );
115             
116             detect_and_draw( frame_copy );
117
118             if( cvWaitKey( 10 ) >= 0 )
119                 goto _cleanup_;
120         }
121
122         cvWaitKey(0);
123 _cleanup_:
124         cvReleaseImage( &frame_copy );
125         cvReleaseCapture( &capture );
126     }
127     else
128     {
129         if( image )
130         {
131             detect_and_draw( image );
132             cvWaitKey(0);
133             cvReleaseImage( &image );
134         }
135         else if( input_name )
136         {
137             /* assume it is a text file containing the
138                list of the image filenames to be processed - one per line */
139             FILE* f = fopen( input_name, "rt" );
140             if( f )
141             {
142                 char buf[1000+1];
143                 while( fgets( buf, 1000, f ) )
144                 {
145                     int len = (int)strlen(buf), c;
146                     while( len > 0 && isspace(buf[len-1]) )
147                         len--;
148                     buf[len] = '\0';
149                     printf( "file %s\n", buf ); 
150                     image = cvLoadImage( buf, 1 );
151                     if( image )
152                     {
153                         detect_and_draw( image );
154                         c = cvWaitKey(0);
155                         if( c == 27 || c == 'q' || c == 'Q' )
156                             break;
157                         cvReleaseImage( &image );
158                     }
159                 }
160                 fclose(f);
161             }
162         }
163     }
164     
165     cvDestroyWindow("result");
166
167     return 0;
168 }
169
170 void detect_and_draw( IplImage* img )
171 {
172     static CvScalar colors[] = 
173     {
174         {{0,0,255}},
175         {{0,128,255}},
176         {{0,255,255}},
177         {{0,255,0}},
178         {{255,128,0}},
179         {{255,255,0}},
180         {{255,0,0}},
181         {{255,0,255}}
182     };
183
184     IplImage *gray, *small_img;
185     int i, j;
186
187     gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
188     small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
189                          cvRound (img->height/scale)), 8, 1 );
190
191     cvCvtColor( img, gray, CV_BGR2GRAY );
192     cvResize( gray, small_img, CV_INTER_LINEAR );
193     cvEqualizeHist( small_img, small_img );
194     cvClearMemStorage( storage );
195
196     if( cascade )
197     {
198         double t = (double)cvGetTickCount();
199         CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
200                                             1.1, 2, 0
201                                             //|CV_HAAR_FIND_BIGGEST_OBJECT
202                                             //|CV_HAAR_DO_ROUGH_SEARCH
203                                             |CV_HAAR_DO_CANNY_PRUNING
204                                             //|CV_HAAR_SCALE_IMAGE
205                                             ,
206                                             cvSize(30, 30) );
207         t = (double)cvGetTickCount() - t;
208         printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
209         for( i = 0; i < (faces ? faces->total : 0); i++ )
210         {
211             CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
212             CvMat small_img_roi;
213             CvSeq* nested_objects;
214             CvPoint center;
215             CvScalar color = colors[i%8];
216             int radius;
217             center.x = cvRound((r->x + r->width*0.5)*scale);
218             center.y = cvRound((r->y + r->height*0.5)*scale);
219             radius = cvRound((r->width + r->height)*0.25*scale);
220             cvCircle( img, center, radius, color, 3, 8, 0 );
221             if( !nested_cascade )
222                 continue;
223             cvGetSubRect( small_img, &small_img_roi, *r );
224             nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,
225                                         1.1, 2, 0
226                                         //|CV_HAAR_FIND_BIGGEST_OBJECT
227                                         //|CV_HAAR_DO_ROUGH_SEARCH
228                                         //|CV_HAAR_DO_CANNY_PRUNING
229                                         //|CV_HAAR_SCALE_IMAGE
230                                         ,
231                                         cvSize(0, 0) );
232             for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )
233             {
234                 CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );
235                 center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
236                 center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
237                 radius = cvRound((nr->width + nr->height)*0.25*scale);
238                 cvCircle( img, center, radius, color, 3, 8, 0 );
239             }
240         }
241     }
242
243     cvShowImage( "result", img );
244     cvReleaseImage( &gray );
245     cvReleaseImage( &small_img );
246 }