1 #include "opencv2/objdetect.hpp"
2 #include "opencv2/highgui.hpp"
3 #include "opencv2/imgproc.hpp"
4 #include "opencv2/core/utility.hpp"
6 #include "opencv2/highgui/highgui_c.h"
18 cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
19 "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
20 "It's most known use is for faces.\n"
22 "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
23 " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
24 " [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
26 " [filename|camera_index]\n\n"
27 "see facedetect.cmd for one call:\n"
28 "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n"
29 "During execution:\n\tHit any key to quit.\n"
30 "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
33 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
34 CascadeClassifier& nestedCascade,
35 double scale, bool tryflip );
37 string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
38 string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
40 int main( int argc, const char** argv )
42 CvCapture* capture = 0;
43 Mat frame, frameCopy, image;
44 const string scaleOpt = "--scale=";
45 size_t scaleOptLen = scaleOpt.length();
46 const string cascadeOpt = "--cascade=";
47 size_t cascadeOptLen = cascadeOpt.length();
48 const string nestedCascadeOpt = "--nested-cascade";
49 size_t nestedCascadeOptLen = nestedCascadeOpt.length();
50 const string tryFlipOpt = "--try-flip";
51 size_t tryFlipOptLen = tryFlipOpt.length();
57 CascadeClassifier cascade, nestedCascade;
60 for( int i = 1; i < argc; i++ )
62 cout << "Processing " << i << " " << argv[i] << endl;
63 if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
65 cascadeName.assign( argv[i] + cascadeOptLen );
66 cout << " from which we have cascadeName= " << cascadeName << endl;
68 else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
70 if( argv[i][nestedCascadeOpt.length()] == '=' )
71 nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
72 if( !nestedCascade.load( nestedCascadeName ) )
73 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
75 else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
77 if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
79 cout << " from which we read scale = " << scale << endl;
81 else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
84 cout << " will try to flip image horizontally to detect assymetric objects\n";
86 else if( argv[i][0] == '-' )
88 cerr << "WARNING: Unknown option %s" << argv[i] << endl;
91 inputName.assign( argv[i] );
94 if( !cascade.load( cascadeName ) )
96 cerr << "ERROR: Could not load classifier cascade" << endl;
101 if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
103 capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
104 int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;
105 if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl;
107 else if( inputName.size() )
109 image = imread( inputName, 1 );
112 capture = cvCaptureFromAVI( inputName.c_str() );
113 if(!capture) cout << "Capture from AVI didn't work" << endl;
118 image = imread( "lena.jpg", 1 );
119 if(image.empty()) cout << "Couldn't read lena.jpg" << endl;
122 cvNamedWindow( "result", 1 );
126 cout << "In capture ..." << endl;
129 IplImage* iplImg = cvQueryFrame( capture );
130 frame = cv::cvarrToMat(iplImg);
133 if( iplImg->origin == IPL_ORIGIN_TL )
134 frame.copyTo( frameCopy );
136 flip( frame, frameCopy, 0 );
138 detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip );
140 if( waitKey( 10 ) >= 0 )
147 cvReleaseCapture( &capture );
151 cout << "In image read" << endl;
154 detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
157 else if( !inputName.empty() )
159 /* assume it is a text file containing the
160 list of the image filenames to be processed - one per line */
161 FILE* f = fopen( inputName.c_str(), "rt" );
165 while( fgets( buf, 1000, f ) )
167 int len = (int)strlen(buf), c;
168 while( len > 0 && isspace(buf[len-1]) )
171 cout << "file " << buf << endl;
172 image = imread( buf, 1 );
175 detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
177 if( c == 27 || c == 'q' || c == 'Q' )
182 cerr << "Aw snap, couldn't read image " << buf << endl;
190 cvDestroyWindow("result");
195 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
196 CascadeClassifier& nestedCascade,
197 double scale, bool tryflip )
201 vector<Rect> faces, faces2;
202 const static Scalar colors[] = { CV_RGB(0,0,255),
210 Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );
212 cvtColor( img, gray, COLOR_BGR2GRAY );
213 resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
214 equalizeHist( smallImg, smallImg );
216 t = (double)cvGetTickCount();
217 cascade.detectMultiScale( smallImg, faces,
219 //|CASCADE_FIND_BIGGEST_OBJECT
220 //|CASCADE_DO_ROUGH_SEARCH
226 flip(smallImg, smallImg, 1);
227 cascade.detectMultiScale( smallImg, faces2,
229 //|CASCADE_FIND_BIGGEST_OBJECT
230 //|CASCADE_DO_ROUGH_SEARCH
234 for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
236 faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
239 t = (double)cvGetTickCount() - t;
240 printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
241 for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
244 vector<Rect> nestedObjects;
246 Scalar color = colors[i%8];
249 double aspect_ratio = (double)r->width/r->height;
250 if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
252 center.x = cvRound((r->x + r->width*0.5)*scale);
253 center.y = cvRound((r->y + r->height*0.5)*scale);
254 radius = cvRound((r->width + r->height)*0.25*scale);
255 circle( img, center, radius, color, 3, 8, 0 );
258 rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
259 cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
261 if( nestedCascade.empty() )
263 smallImgROI = smallImg(*r);
264 nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
266 //|CASCADE_FIND_BIGGEST_OBJECT
267 //|CASCADE_DO_ROUGH_SEARCH
268 //|CASCADE_DO_CANNY_PRUNING
272 for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
274 center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
275 center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
276 radius = cvRound((nr->width + nr->height)*0.25*scale);
277 circle( img, center, radius, color, 3, 8, 0 );
280 cv::imshow( "result", img );