updated logistic regression sample program
[profile/ivi/opencv.git] / samples / cpp / ufacedetect.cpp
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"
8
9 #include <cctype>
10 #include <iostream>
11 #include <iterator>
12 #include <stdio.h>
13
14 using namespace std;
15 using namespace cv;
16
17 static void help()
18 {
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"
22             "Usage:\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"
26                "   [--try-flip]\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;
32 }
33
34 void detectAndDraw( UMat& img, Mat& canvas, CascadeClassifier& cascade,
35                     CascadeClassifier& nestedCascade,
36                     double scale, bool tryflip );
37
38 string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
39 string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
40
41 int main( int argc, const char** argv )
42 {
43     VideoCapture capture;
44     UMat frame, image;
45     Mat canvas;
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();
54     String inputName;
55     bool tryflip = false;
56
57     help();
58
59     CascadeClassifier cascade, nestedCascade;
60     double scale = 1;
61
62     for( int i = 1; i < argc; i++ )
63     {
64         cout << "Processing " << i << " " <<  argv[i] << endl;
65         if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
66         {
67             cascadeName.assign( argv[i] + cascadeOptLen );
68             cout << "  from which we have cascadeName= " << cascadeName << endl;
69         }
70         else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
71         {
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;
76         }
77         else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
78         {
79             if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale > 1 )
80                 scale = 1;
81             cout << " from which we read scale = " << scale << endl;
82         }
83         else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
84         {
85             tryflip = true;
86             cout << " will try to flip image horizontally to detect assymetric objects\n";
87         }
88         else if( argv[i][0] == '-' )
89         {
90             cerr << "WARNING: Unknown option %s" << argv[i] << endl;
91         }
92         else
93             inputName = argv[i];
94     }
95
96     if( !cascade.load( cascadeName ) )
97     {
98         cerr << "ERROR: Could not load classifier cascade" << endl;
99         help();
100         return -1;
101     }
102
103     cout << "old cascade: " << (cascade.isOldFormatCascade() ? "TRUE" : "FALSE") << endl;
104
105     if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
106     {
107         int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0';
108         if(!capture.open(c))
109             cout << "Capture from camera #" <<  c << " didn't work" << endl;
110     }
111     else
112     {
113         if( inputName.empty() )
114             inputName = "lena.jpg";
115         image = imread( inputName, 1 ).getUMat(ACCESS_READ);
116         if( image.empty() )
117         {
118             if(!capture.open( inputName ))
119                 cout << "Could not read " << inputName << endl;
120         }
121     }
122
123     namedWindow( "result", 1 );
124
125     if( capture.isOpened() )
126     {
127         cout << "Video capturing has been started ..." << endl;
128         for(;;)
129         {
130             capture >> frame;
131             if( frame.empty() )
132                 break;
133
134             detectAndDraw( frame, canvas, cascade, nestedCascade, scale, tryflip );
135
136             if( waitKey( 10 ) >= 0 )
137                 break;
138         }
139     }
140     else
141     {
142         cout << "Detecting face(s) in " << inputName << endl;
143         if( !image.empty() )
144         {
145             detectAndDraw( image, canvas, cascade, nestedCascade, scale, tryflip );
146             waitKey(0);
147         }
148         else if( !inputName.empty() )
149         {
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" );
153             if( f )
154             {
155                 char buf[1000+1];
156                 while( fgets( buf, 1000, f ) )
157                 {
158                     int len = (int)strlen(buf), c;
159                     while( len > 0 && isspace(buf[len-1]) )
160                         len--;
161                     buf[len] = '\0';
162                     cout << "file " << buf << endl;
163                     image = imread( buf, 1 ).getUMat(ACCESS_READ);
164                     if( !image.empty() )
165                     {
166                         detectAndDraw( image, canvas, cascade, nestedCascade, scale, tryflip );
167                         c = waitKey(0);
168                         if( c == 27 || c == 'q' || c == 'Q' )
169                             break;
170                     }
171                     else
172                     {
173                         cerr << "Aw snap, couldn't read image " << buf << endl;
174                     }
175                 }
176                 fclose(f);
177             }
178         }
179     }
180
181     return 0;
182 }
183
184 void detectAndDraw( UMat& img, Mat& canvas, CascadeClassifier& cascade,
185                     CascadeClassifier& nestedCascade,
186                     double scale0, bool tryflip )
187 {
188     int i = 0;
189     double t = 0, scale=1;
190     vector<Rect> faces, faces2;
191     const static Scalar colors[] =
192     {
193         Scalar(0,0,255),
194         Scalar(0,128,255),
195         Scalar(0,255,255),
196         Scalar(0,255,0),
197         Scalar(255,128,0),
198         Scalar(255,255,0),
199         Scalar(255,0,0),
200         Scalar(255,0,255)
201     };
202     static UMat gray, smallImg;
203
204     t = (double)getTickCount();
205
206     resize( img, smallImg, Size(), scale0, scale0, INTER_LINEAR );
207     cvtColor( smallImg, gray, COLOR_BGR2GRAY );
208     equalizeHist( gray, gray );
209
210     cascade.detectMultiScale( gray, faces,
211         1.1, 3, 0
212         //|CASCADE_FIND_BIGGEST_OBJECT
213         //|CASCADE_DO_ROUGH_SEARCH
214         |CASCADE_SCALE_IMAGE
215         ,
216         Size(30, 30) );
217     if( tryflip )
218     {
219         flip(gray, gray, 1);
220         cascade.detectMultiScale( gray, faces2,
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         for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
228         {
229             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
230         }
231     }
232     t = (double)getTickCount() - t;
233     smallImg.copyTo(canvas);
234
235     double fps = getTickFrequency()/t;
236     static double avgfps = 0;
237     static int nframes = 0;
238     nframes++;
239     double alpha = nframes > 50 ? 0.01 : 1./nframes;
240     avgfps = avgfps*(1-alpha) + fps*alpha;
241
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);
244
245     for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
246     {
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( canvas, center, radius, color, 3, 8, 0 );
259         }
260         else
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)),
263                        color, 3, 8, 0);
264         if( nestedCascade.empty() )
265             continue;
266         UMat smallImgROI = gray(*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( canvas, center, radius, color, 3, 8, 0 );
281         }
282     }
283     imshow( "result", canvas );
284 }