Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/cpp/facedetect.cpp
16337 views
1
#include "opencv2/objdetect.hpp"
2
#include "opencv2/highgui.hpp"
3
#include "opencv2/imgproc.hpp"
4
#include <iostream>
5
6
using namespace std;
7
using namespace cv;
8
9
static void help()
10
{
11
cout << "\nThis program demonstrates the use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n"
12
"This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
13
"It's most known use is for faces.\n"
14
"Usage:\n"
15
"./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
16
" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
17
" [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
18
" [--try-flip]\n"
19
" [filename|camera_index]\n\n"
20
"see facedetect.cmd for one call:\n"
21
"./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n"
22
"During execution:\n\tHit any key to quit.\n"
23
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
24
}
25
26
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
27
CascadeClassifier& nestedCascade,
28
double scale, bool tryflip );
29
30
string cascadeName;
31
string nestedCascadeName;
32
33
int main( int argc, const char** argv )
34
{
35
VideoCapture capture;
36
Mat frame, image;
37
string inputName;
38
bool tryflip;
39
CascadeClassifier cascade, nestedCascade;
40
double scale;
41
42
cv::CommandLineParser parser(argc, argv,
43
"{help h||}"
44
"{cascade|../../data/haarcascades/haarcascade_frontalface_alt.xml|}"
45
"{nested-cascade|../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}"
46
"{scale|1|}{try-flip||}{@filename||}"
47
);
48
if (parser.has("help"))
49
{
50
help();
51
return 0;
52
}
53
cascadeName = parser.get<string>("cascade");
54
nestedCascadeName = parser.get<string>("nested-cascade");
55
scale = parser.get<double>("scale");
56
if (scale < 1)
57
scale = 1;
58
tryflip = parser.has("try-flip");
59
inputName = parser.get<string>("@filename");
60
if (!parser.check())
61
{
62
parser.printErrors();
63
return 0;
64
}
65
if ( !nestedCascade.load( nestedCascadeName ) )
66
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
67
if( !cascade.load( cascadeName ) )
68
{
69
cerr << "ERROR: Could not load classifier cascade" << endl;
70
help();
71
return -1;
72
}
73
if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
74
{
75
int camera = inputName.empty() ? 0 : inputName[0] - '0';
76
if(!capture.open(camera))
77
cout << "Capture from camera #" << camera << " didn't work" << endl;
78
}
79
else if( inputName.size() )
80
{
81
image = imread( inputName, 1 );
82
if( image.empty() )
83
{
84
if(!capture.open( inputName ))
85
cout << "Could not read " << inputName << endl;
86
}
87
}
88
else
89
{
90
image = imread( "../data/lena.jpg", 1 );
91
if(image.empty()) cout << "Couldn't read ../data/lena.jpg" << endl;
92
}
93
94
if( capture.isOpened() )
95
{
96
cout << "Video capturing has been started ..." << endl;
97
98
for(;;)
99
{
100
capture >> frame;
101
if( frame.empty() )
102
break;
103
104
Mat frame1 = frame.clone();
105
detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
106
107
char c = (char)waitKey(10);
108
if( c == 27 || c == 'q' || c == 'Q' )
109
break;
110
}
111
}
112
else
113
{
114
cout << "Detecting face(s) in " << inputName << endl;
115
if( !image.empty() )
116
{
117
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
118
waitKey(0);
119
}
120
else if( !inputName.empty() )
121
{
122
/* assume it is a text file containing the
123
list of the image filenames to be processed - one per line */
124
FILE* f = fopen( inputName.c_str(), "rt" );
125
if( f )
126
{
127
char buf[1000+1];
128
while( fgets( buf, 1000, f ) )
129
{
130
int len = (int)strlen(buf);
131
while( len > 0 && isspace(buf[len-1]) )
132
len--;
133
buf[len] = '\0';
134
cout << "file " << buf << endl;
135
image = imread( buf, 1 );
136
if( !image.empty() )
137
{
138
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
139
char c = (char)waitKey(0);
140
if( c == 27 || c == 'q' || c == 'Q' )
141
break;
142
}
143
else
144
{
145
cerr << "Aw snap, couldn't read image " << buf << endl;
146
}
147
}
148
fclose(f);
149
}
150
}
151
}
152
153
return 0;
154
}
155
156
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
157
CascadeClassifier& nestedCascade,
158
double scale, bool tryflip )
159
{
160
double t = 0;
161
vector<Rect> faces, faces2;
162
const static Scalar colors[] =
163
{
164
Scalar(255,0,0),
165
Scalar(255,128,0),
166
Scalar(255,255,0),
167
Scalar(0,255,0),
168
Scalar(0,128,255),
169
Scalar(0,255,255),
170
Scalar(0,0,255),
171
Scalar(255,0,255)
172
};
173
Mat gray, smallImg;
174
175
cvtColor( img, gray, COLOR_BGR2GRAY );
176
double fx = 1 / scale;
177
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
178
equalizeHist( smallImg, smallImg );
179
180
t = (double)getTickCount();
181
cascade.detectMultiScale( smallImg, faces,
182
1.1, 2, 0
183
//|CASCADE_FIND_BIGGEST_OBJECT
184
//|CASCADE_DO_ROUGH_SEARCH
185
|CASCADE_SCALE_IMAGE,
186
Size(30, 30) );
187
if( tryflip )
188
{
189
flip(smallImg, smallImg, 1);
190
cascade.detectMultiScale( smallImg, faces2,
191
1.1, 2, 0
192
//|CASCADE_FIND_BIGGEST_OBJECT
193
//|CASCADE_DO_ROUGH_SEARCH
194
|CASCADE_SCALE_IMAGE,
195
Size(30, 30) );
196
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
197
{
198
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
199
}
200
}
201
t = (double)getTickCount() - t;
202
printf( "detection time = %g ms\n", t*1000/getTickFrequency());
203
for ( size_t i = 0; i < faces.size(); i++ )
204
{
205
Rect r = faces[i];
206
Mat smallImgROI;
207
vector<Rect> nestedObjects;
208
Point center;
209
Scalar color = colors[i%8];
210
int radius;
211
212
double aspect_ratio = (double)r.width/r.height;
213
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
214
{
215
center.x = cvRound((r.x + r.width*0.5)*scale);
216
center.y = cvRound((r.y + r.height*0.5)*scale);
217
radius = cvRound((r.width + r.height)*0.25*scale);
218
circle( img, center, radius, color, 3, 8, 0 );
219
}
220
else
221
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
222
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
223
color, 3, 8, 0);
224
if( nestedCascade.empty() )
225
continue;
226
smallImgROI = smallImg( r );
227
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
228
1.1, 2, 0
229
//|CASCADE_FIND_BIGGEST_OBJECT
230
//|CASCADE_DO_ROUGH_SEARCH
231
//|CASCADE_DO_CANNY_PRUNING
232
|CASCADE_SCALE_IMAGE,
233
Size(30, 30) );
234
for ( size_t j = 0; j < nestedObjects.size(); j++ )
235
{
236
Rect nr = nestedObjects[j];
237
center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
238
center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
239
radius = cvRound((nr.width + nr.height)*0.25*scale);
240
circle( img, center, radius, color, 3, 8, 0 );
241
}
242
}
243
imshow( "result", img );
244
}
245
246