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 }
247