• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "opencv2/videoio/videoio_c.h"
9 #include "opencv2/highgui/highgui_c.h"
10 
11 #include <cctype>
12 #include <iostream>
13 #include <iterator>
14 #include <stdio.h>
15 
16 using namespace std;
17 using namespace cv;
18 
help()19 static void help()
20 {
21     cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
22             "This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
23             "It's most known use is for faces.\n"
24             "Usage:\n"
25             "./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
26                "   [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
27                "   [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
28                "   [--try-flip]\n"
29                "   [filename|camera_index]\n\n"
30             "see facedetect.cmd for one call:\n"
31             "./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n"
32             "During execution:\n\tHit any key to quit.\n"
33             "\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
34 }
35 
36 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
37                     CascadeClassifier& nestedCascade,
38                     double scale, bool tryflip );
39 
40 string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
41 string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
42 
main(int argc,const char ** argv)43 int main( int argc, const char** argv )
44 {
45     CvCapture* capture = 0;
46     Mat frame, frameCopy, image;
47     const string scaleOpt = "--scale=";
48     size_t scaleOptLen = scaleOpt.length();
49     const string cascadeOpt = "--cascade=";
50     size_t cascadeOptLen = cascadeOpt.length();
51     const string nestedCascadeOpt = "--nested-cascade";
52     size_t nestedCascadeOptLen = nestedCascadeOpt.length();
53     const string tryFlipOpt = "--try-flip";
54     size_t tryFlipOptLen = tryFlipOpt.length();
55     string inputName;
56     bool tryflip = false;
57 
58     help();
59 
60     CascadeClassifier cascade, nestedCascade;
61     double scale = 1;
62 
63     for( int i = 1; i < argc; i++ )
64     {
65         cout << "Processing " << i << " " <<  argv[i] << endl;
66         if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
67         {
68             cascadeName.assign( argv[i] + cascadeOptLen );
69             cout << "  from which we have cascadeName= " << cascadeName << endl;
70         }
71         else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
72         {
73             if( argv[i][nestedCascadeOpt.length()] == '=' )
74                 nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
75             if( !nestedCascade.load( nestedCascadeName ) )
76                 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
77         }
78         else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
79         {
80             if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
81                 scale = 1;
82             cout << " from which we read scale = " << scale << endl;
83         }
84         else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
85         {
86             tryflip = true;
87             cout << " will try to flip image horizontally to detect assymetric objects\n";
88         }
89         else if( argv[i][0] == '-' )
90         {
91             cerr << "WARNING: Unknown option %s" << argv[i] << endl;
92         }
93         else
94             inputName.assign( argv[i] );
95     }
96 
97     if( !cascade.load( cascadeName ) )
98     {
99         cerr << "ERROR: Could not load classifier cascade" << endl;
100         help();
101         return -1;
102     }
103 
104     if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
105     {
106         capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
107         int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;
108         if(!capture) cout << "Capture from CAM " <<  c << " didn't work" << endl;
109     }
110     else if( inputName.size() )
111     {
112         image = imread( inputName, 1 );
113         if( image.empty() )
114         {
115             capture = cvCaptureFromAVI( inputName.c_str() );
116             if(!capture) cout << "Capture from AVI didn't work" << endl;
117         }
118     }
119     else
120     {
121         image = imread( "../data/lena.jpg", 1 );
122         if(image.empty()) cout << "Couldn't read ../data/lena.jpg" << endl;
123     }
124 
125     cvNamedWindow( "result", 1 );
126 
127     if( capture )
128     {
129         cout << "In capture ..." << endl;
130         for(;;)
131         {
132             IplImage* iplImg = cvQueryFrame( capture );
133             frame = cv::cvarrToMat(iplImg);
134             if( frame.empty() )
135                 break;
136             if( iplImg->origin == IPL_ORIGIN_TL )
137                 frame.copyTo( frameCopy );
138             else
139                 flip( frame, frameCopy, 0 );
140 
141             detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip );
142 
143             if( waitKey( 10 ) >= 0 )
144                 goto _cleanup_;
145         }
146 
147         waitKey(0);
148 
149 _cleanup_:
150         cvReleaseCapture( &capture );
151     }
152     else
153     {
154         cout << "In image read" << endl;
155         if( !image.empty() )
156         {
157             detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
158             waitKey(0);
159         }
160         else if( !inputName.empty() )
161         {
162             /* assume it is a text file containing the
163             list of the image filenames to be processed - one per line */
164             FILE* f = fopen( inputName.c_str(), "rt" );
165             if( f )
166             {
167                 char buf[1000+1];
168                 while( fgets( buf, 1000, f ) )
169                 {
170                     int len = (int)strlen(buf), c;
171                     while( len > 0 && isspace(buf[len-1]) )
172                         len--;
173                     buf[len] = '\0';
174                     cout << "file " << buf << endl;
175                     image = imread( buf, 1 );
176                     if( !image.empty() )
177                     {
178                         detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
179                         c = waitKey(0);
180                         if( c == 27 || c == 'q' || c == 'Q' )
181                             break;
182                     }
183                     else
184                     {
185                         cerr << "Aw snap, couldn't read image " << buf << endl;
186                     }
187                 }
188                 fclose(f);
189             }
190         }
191     }
192 
193     cvDestroyWindow("result");
194 
195     return 0;
196 }
197 
detectAndDraw(Mat & img,CascadeClassifier & cascade,CascadeClassifier & nestedCascade,double scale,bool tryflip)198 void detectAndDraw( Mat& img, CascadeClassifier& cascade,
199                     CascadeClassifier& nestedCascade,
200                     double scale, bool tryflip )
201 {
202     int i = 0;
203     double t = 0;
204     vector<Rect> faces, faces2;
205     const static Scalar colors[] =  { CV_RGB(0,0,255),
206         CV_RGB(0,128,255),
207         CV_RGB(0,255,255),
208         CV_RGB(0,255,0),
209         CV_RGB(255,128,0),
210         CV_RGB(255,255,0),
211         CV_RGB(255,0,0),
212         CV_RGB(255,0,255)} ;
213     Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );
214 
215     cvtColor( img, gray, COLOR_BGR2GRAY );
216     resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
217     equalizeHist( smallImg, smallImg );
218 
219     t = (double)cvGetTickCount();
220     cascade.detectMultiScale( smallImg, faces,
221         1.1, 2, 0
222         //|CASCADE_FIND_BIGGEST_OBJECT
223         //|CASCADE_DO_ROUGH_SEARCH
224         |CASCADE_SCALE_IMAGE
225         ,
226         Size(30, 30) );
227     if( tryflip )
228     {
229         flip(smallImg, smallImg, 1);
230         cascade.detectMultiScale( smallImg, faces2,
231                                  1.1, 2, 0
232                                  //|CASCADE_FIND_BIGGEST_OBJECT
233                                  //|CASCADE_DO_ROUGH_SEARCH
234                                  |CASCADE_SCALE_IMAGE
235                                  ,
236                                  Size(30, 30) );
237         for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
238         {
239             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
240         }
241     }
242     t = (double)cvGetTickCount() - t;
243     printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
244     for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
245     {
246         Mat smallImgROI;
247         vector<Rect> nestedObjects;
248         Point center;
249         Scalar color = colors[i%8];
250         int radius;
251 
252         double aspect_ratio = (double)r->width/r->height;
253         if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
254         {
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( img, center, radius, color, 3, 8, 0 );
259         }
260         else
261             rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
262                        cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
263                        color, 3, 8, 0);
264         if( nestedCascade.empty() )
265             continue;
266         smallImgROI = smallImg(*r);
267         nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
268             1.1, 2, 0
269             //|CASCADE_FIND_BIGGEST_OBJECT
270             //|CASCADE_DO_ROUGH_SEARCH
271             //|CASCADE_DO_CANNY_PRUNING
272             |CASCADE_SCALE_IMAGE
273             ,
274             Size(30, 30) );
275         for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
276         {
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( img, center, radius, color, 3, 8, 0 );
281         }
282     }
283     cv::imshow( "result", img );
284 }
285