1 #include "opencv2/objdetect.hpp"
2 #include "opencv2/imgcodecs.hpp"
3 #include "opencv2/videoio.hpp"
4 #include "opencv2/highgui.hpp"
5 #include "opencv2/imgproc.hpp"
6 #include "opencv2/core/utility.hpp"
7 #include "opencv2/core/ocl.hpp"
19 cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
20 "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
21 "It's most known use is for faces.\n"
23 "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
24 " [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
25 " [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
27 " [filename|camera_index]\n\n"
28 "see facedetect.cmd for one call:\n"
29 "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n"
30 "During execution:\n\tHit any key to quit.\n"
31 "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
34 void detectAndDraw( UMat& img, Mat& canvas, CascadeClassifier& cascade,
35 CascadeClassifier& nestedCascade,
36 double scale, bool tryflip );
38 string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
39 string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
41 int main( int argc, const char** argv )
46 const string scaleOpt = "--scale=";
47 size_t scaleOptLen = scaleOpt.length();
48 const string cascadeOpt = "--cascade=";
49 size_t cascadeOptLen = cascadeOpt.length();
50 const string nestedCascadeOpt = "--nested-cascade";
51 size_t nestedCascadeOptLen = nestedCascadeOpt.length();
52 const string tryFlipOpt = "--try-flip";
53 size_t tryFlipOptLen = tryFlipOpt.length();
59 CascadeClassifier cascade, nestedCascade;
62 for( int i = 1; i < argc; i++ )
64 cout << "Processing " << i << " " << argv[i] << endl;
65 if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
67 cascadeName.assign( argv[i] + cascadeOptLen );
68 cout << " from which we have cascadeName= " << cascadeName << endl;
70 else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
72 if( argv[i][nestedCascadeOpt.length()] == '=' )
73 nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
74 if( !nestedCascade.load( nestedCascadeName ) )
75 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
77 else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
79 if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale > 1 )
81 cout << " from which we read scale = " << scale << endl;
83 else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
86 cout << " will try to flip image horizontally to detect assymetric objects\n";
88 else if( argv[i][0] == '-' )
90 cerr << "WARNING: Unknown option %s" << argv[i] << endl;
96 if( !cascade.load( cascadeName ) )
98 cerr << "ERROR: Could not load classifier cascade" << endl;
103 cout << "old cascade: " << (cascade.isOldFormatCascade() ? "TRUE" : "FALSE") << endl;
105 if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
107 int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0';
109 cout << "Capture from camera #" << c << " didn't work" << endl;
113 if( inputName.empty() )
114 inputName = "lena.jpg";
115 image = imread( inputName, 1 ).getUMat(ACCESS_READ);
118 if(!capture.open( inputName ))
119 cout << "Could not read " << inputName << endl;
123 namedWindow( "result", 1 );
125 if( capture.isOpened() )
127 cout << "Video capturing has been started ..." << endl;
134 detectAndDraw( frame, canvas, cascade, nestedCascade, scale, tryflip );
136 if( waitKey( 10 ) >= 0 )
142 cout << "Detecting face(s) in " << inputName << endl;
145 detectAndDraw( image, canvas, cascade, nestedCascade, scale, tryflip );
148 else if( !inputName.empty() )
150 /* assume it is a text file containing the
151 list of the image filenames to be processed - one per line */
152 FILE* f = fopen( inputName.c_str(), "rt" );
156 while( fgets( buf, 1000, f ) )
158 int len = (int)strlen(buf), c;
159 while( len > 0 && isspace(buf[len-1]) )
162 cout << "file " << buf << endl;
163 image = imread( buf, 1 ).getUMat(ACCESS_READ);
166 detectAndDraw( image, canvas, cascade, nestedCascade, scale, tryflip );
168 if( c == 27 || c == 'q' || c == 'Q' )
173 cerr << "Aw snap, couldn't read image " << buf << endl;
184 void detectAndDraw( UMat& img, Mat& canvas, CascadeClassifier& cascade,
185 CascadeClassifier& nestedCascade,
186 double scale0, bool tryflip )
189 double t = 0, scale=1;
190 vector<Rect> faces, faces2;
191 const static Scalar colors[] =
202 static UMat gray, smallImg;
204 t = (double)getTickCount();
206 resize( img, smallImg, Size(), scale0, scale0, INTER_LINEAR );
207 cvtColor( smallImg, gray, COLOR_BGR2GRAY );
208 equalizeHist( gray, gray );
210 cascade.detectMultiScale( gray, faces,
212 //|CASCADE_FIND_BIGGEST_OBJECT
213 //|CASCADE_DO_ROUGH_SEARCH
220 cascade.detectMultiScale( gray, faces2,
222 //|CASCADE_FIND_BIGGEST_OBJECT
223 //|CASCADE_DO_ROUGH_SEARCH
227 for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
229 faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
232 t = (double)getTickCount() - t;
233 smallImg.copyTo(canvas);
235 double fps = getTickFrequency()/t;
236 static double avgfps = 0;
237 static int nframes = 0;
239 double alpha = nframes > 50 ? 0.01 : 1./nframes;
240 avgfps = avgfps*(1-alpha) + fps*alpha;
242 putText(canvas, format("OpenCL: %s, fps: %.1f", ocl::useOpenCL() ? "ON" : "OFF", avgfps), Point(50, 30),
243 FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0,255,0), 2);
245 for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
247 vector<Rect> nestedObjects;
249 Scalar color = colors[i%8];
252 double aspect_ratio = (double)r->width/r->height;
253 if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
255 center.x = cvRound((r->x + r->width*0.5)*scale);
256 center.y = cvRound((r->y + r->height*0.5)*scale);
257 radius = cvRound((r->width + r->height)*0.25*scale);
258 circle( canvas, center, radius, color, 3, 8, 0 );
261 rectangle( canvas, Point(cvRound(r->x*scale), cvRound(r->y*scale)),
262 Point(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
264 if( nestedCascade.empty() )
266 UMat smallImgROI = gray(*r);
267 nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
269 //|CASCADE_FIND_BIGGEST_OBJECT
270 //|CASCADE_DO_ROUGH_SEARCH
271 //|CASCADE_DO_CANNY_PRUNING
275 for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
277 center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
278 center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
279 radius = cvRound((nr->width + nr->height)*0.25*scale);
280 circle( canvas, center, radius, color, 3, 8, 0 );
283 imshow( "result", canvas );