Update to 2.0.0 tree from current Fremantle build
[opencv] / samples / c / facedetect.cpp
1 #define CV_NO_BACKWARD_COMPATIBILITY
2
3 #include "cv.h"
4 #include "highgui.h"
5
6 #include <iostream>
7 #include <cstdio>
8
9 #ifdef _EiC
10 #define WIN32
11 #endif
12
13 using namespace std;
14 using namespace cv;
15
16 void detectAndDraw( Mat& img,
17                    CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
18                    double scale);
19
20 String cascadeName =
21 "../../data/haarcascades/haarcascade_frontalface_alt.xml";
22 String nestedCascadeName =
23 "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
24
25 int main( int argc, const char** argv )
26 {
27     CvCapture* capture = 0;
28     Mat frame, frameCopy, image;
29     const String scaleOpt = "--scale=";
30     size_t scaleOptLen = scaleOpt.length();
31     const String cascadeOpt = "--cascade=";
32     size_t cascadeOptLen = cascadeOpt.length();
33     const String nestedCascadeOpt = "--nested-cascade";
34     size_t nestedCascadeOptLen = nestedCascadeOpt.length();
35     String inputName;
36
37     CascadeClassifier cascade, nestedCascade;
38     double scale = 1;
39
40     for( int i = 1; i < argc; i++ )
41     {
42         if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
43             cascadeName.assign( argv[i] + cascadeOptLen );
44         else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
45         {
46             if( argv[i][nestedCascadeOpt.length()] == '=' )
47                 nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
48             if( !nestedCascade.load( nestedCascadeName ) )
49                 cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
50         }
51         else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
52         {
53             if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
54                 scale = 1;
55         }
56         else if( argv[i][0] == '-' )
57         {
58             cerr << "WARNING: Unknown option %s" << argv[i] << endl;
59         }
60         else
61             inputName.assign( argv[i] );
62     }
63
64     if( !cascade.load( cascadeName ) )
65     {
66         cerr << "ERROR: Could not load classifier cascade" << endl;
67         cerr << "Usage: facedetect [--cascade=\"<cascade_path>\"]\n"
68             "   [--nested-cascade[=\"nested_cascade_path\"]]\n"
69             "   [--scale[=<image scale>\n"
70             "   [filename|camera_index]\n" ;
71         return -1;
72     }
73
74     if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
75         capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
76     else if( inputName.size() )
77     {
78         image = imread( inputName, 1 );
79         if( image.empty() )
80             capture = cvCaptureFromAVI( inputName.c_str() );
81     }
82     else
83         image = imread( "lena.jpg", 1 );
84
85     cvNamedWindow( "result", 1 );
86
87     if( capture )
88     {
89         for(;;)
90         {
91             IplImage* iplImg = cvQueryFrame( capture );
92             frame = iplImg;
93             if( frame.empty() )
94                 break;
95             if( iplImg->origin == IPL_ORIGIN_TL )
96                 frame.copyTo( frameCopy );
97             else
98                 flip( frame, frameCopy, 0 );
99
100             detectAndDraw( frameCopy, cascade, nestedCascade, scale );
101
102             if( waitKey( 10 ) >= 0 )
103                 goto _cleanup_;
104         }
105
106         waitKey(0);
107 _cleanup_:
108         cvReleaseCapture( &capture );
109     }
110     else
111     {
112         if( !image.empty() )
113         {
114             detectAndDraw( image, cascade, nestedCascade, scale );
115             waitKey(0);
116         }
117         else if( !inputName.empty() )
118         {
119             /* assume it is a text file containing the
120             list of the image filenames to be processed - one per line */
121             FILE* f = fopen( inputName.c_str(), "rt" );
122             if( f )
123             {
124                 char buf[1000+1];
125                 while( fgets( buf, 1000, f ) )
126                 {
127                     int len = (int)strlen(buf), c;
128                     while( len > 0 && isspace(buf[len-1]) )
129                         len--;
130                     buf[len] = '\0';
131                     cout << "file " << buf << endl;
132                     image = imread( buf, 1 );
133                     if( !image.empty() )
134                     {
135                         detectAndDraw( image, cascade, nestedCascade, scale );
136                         c = waitKey(0);
137                         if( c == 27 || c == 'q' || c == 'Q' )
138                             break;
139                     }
140                 }
141                 fclose(f);
142             }
143         }
144     }
145
146     cvDestroyWindow("result");
147
148     return 0;
149 }
150
151 void detectAndDraw( Mat& img,
152                    CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
153                    double scale)
154 {
155     int i = 0;
156     double t = 0;
157     vector<Rect> faces;
158     const static Scalar colors[] =  { CV_RGB(0,0,255),
159         CV_RGB(0,128,255),
160         CV_RGB(0,255,255),
161         CV_RGB(0,255,0),
162         CV_RGB(255,128,0),
163         CV_RGB(255,255,0),
164         CV_RGB(255,0,0),
165         CV_RGB(255,0,255)} ;
166     Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );
167
168     cvtColor( img, gray, CV_BGR2GRAY );
169     resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
170     equalizeHist( smallImg, smallImg );
171
172     t = (double)cvGetTickCount();
173     cascade.detectMultiScale( smallImg, faces,
174         1.1, 2, 0
175         //|CV_HAAR_FIND_BIGGEST_OBJECT
176         //|CV_HAAR_DO_ROUGH_SEARCH
177         |CV_HAAR_SCALE_IMAGE
178         ,
179         Size(30, 30) );
180     t = (double)cvGetTickCount() - t;
181     printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
182     for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
183     {
184         Mat smallImgROI;
185         vector<Rect> nestedObjects;
186         Point center;
187         Scalar color = colors[i%8];
188         int radius;
189         center.x = cvRound((r->x + r->width*0.5)*scale);
190         center.y = cvRound((r->y + r->height*0.5)*scale);
191         radius = cvRound((r->width + r->height)*0.25*scale);
192         circle( img, center, radius, color, 3, 8, 0 );
193         if( nestedCascade.empty() )
194             continue;
195         smallImgROI = smallImg(*r);
196         nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
197             1.1, 2, 0
198             //|CV_HAAR_FIND_BIGGEST_OBJECT
199             //|CV_HAAR_DO_ROUGH_SEARCH
200             //|CV_HAAR_DO_CANNY_PRUNING
201             |CV_HAAR_SCALE_IMAGE
202             ,
203             Size(30, 30) );
204         for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
205         {
206             center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
207             center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
208             radius = cvRound((nr->width + nr->height)*0.25*scale);
209             circle( img, center, radius, color, 3, 8, 0 );
210         }
211     }  
212     cv::imshow( "result", img );    
213 }