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