1 // WARNING: this sample is under construction! Use it on your own risk.
2 #if defined _MSC_VER && _MSC_VER >= 1400
3 #pragma warning(disable : 4100)
4 #endif
5
6
7 #include <iostream>
8 #include <iomanip>
9 #include "opencv2/objdetect/objdetect.hpp"
10 #include "opencv2/highgui/highgui.hpp"
11 #include "opencv2/imgproc/imgproc.hpp"
12 #include "opencv2/cudaobjdetect.hpp"
13 #include "opencv2/cudaimgproc.hpp"
14 #include "opencv2/cudawarping.hpp"
15
16 #include "tick_meter.hpp"
17
18 using namespace std;
19 using namespace cv;
20 using namespace cv::cuda;
21
22
help()23 static void help()
24 {
25 cout << "Usage: ./cascadeclassifier_gpu \n\t--cascade <cascade_file>\n\t(<image>|--video <video>|--camera <camera_id>)\n"
26 "Using OpenCV version " << CV_VERSION << endl << endl;
27 }
28
29
convertAndResize(const Mat & src,Mat & gray,Mat & resized,double scale)30 static void convertAndResize(const Mat& src, Mat& gray, Mat& resized, double scale)
31 {
32 if (src.channels() == 3)
33 {
34 cv::cvtColor( src, gray, COLOR_BGR2GRAY );
35 }
36 else
37 {
38 gray = src;
39 }
40
41 Size sz(cvRound(gray.cols * scale), cvRound(gray.rows * scale));
42
43 if (scale != 1)
44 {
45 cv::resize(gray, resized, sz);
46 }
47 else
48 {
49 resized = gray;
50 }
51 }
52
convertAndResize(const GpuMat & src,GpuMat & gray,GpuMat & resized,double scale)53 static void convertAndResize(const GpuMat& src, GpuMat& gray, GpuMat& resized, double scale)
54 {
55 if (src.channels() == 3)
56 {
57 cv::cuda::cvtColor( src, gray, COLOR_BGR2GRAY );
58 }
59 else
60 {
61 gray = src;
62 }
63
64 Size sz(cvRound(gray.cols * scale), cvRound(gray.rows * scale));
65
66 if (scale != 1)
67 {
68 cv::cuda::resize(gray, resized, sz);
69 }
70 else
71 {
72 resized = gray;
73 }
74 }
75
76
matPrint(Mat & img,int lineOffsY,Scalar fontColor,const string & ss)77 static void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const string &ss)
78 {
79 int fontFace = FONT_HERSHEY_DUPLEX;
80 double fontScale = 0.8;
81 int fontThickness = 2;
82 Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
83
84 Point org;
85 org.x = 1;
86 org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
87 putText(img, ss, org, fontFace, fontScale, Scalar(0,0,0), 5*fontThickness/2, 16);
88 putText(img, ss, org, fontFace, fontScale, fontColor, fontThickness, 16);
89 }
90
91
displayState(Mat & canvas,bool bHelp,bool bGpu,bool bLargestFace,bool bFilter,double fps)92 static void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bFilter, double fps)
93 {
94 Scalar fontColorRed = Scalar(255,0,0);
95 Scalar fontColorNV = Scalar(118,185,0);
96
97 ostringstream ss;
98 ss << "FPS = " << setprecision(1) << fixed << fps;
99 matPrint(canvas, 0, fontColorRed, ss.str());
100 ss.str("");
101 ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
102 (bGpu ? "GPU, " : "CPU, ") <<
103 (bLargestFace ? "OneFace, " : "MultiFace, ") <<
104 (bFilter ? "Filter:ON" : "Filter:OFF");
105 matPrint(canvas, 1, fontColorRed, ss.str());
106
107 // by Anatoly. MacOS fix. ostringstream(const string&) is a private
108 // matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
109 if (bHelp)
110 {
111 matPrint(canvas, 2, fontColorNV, "Space - switch GPU / CPU");
112 matPrint(canvas, 3, fontColorNV, "M - switch OneFace / MultiFace");
113 matPrint(canvas, 4, fontColorNV, "F - toggle rectangles Filter");
114 matPrint(canvas, 5, fontColorNV, "H - toggle hotkeys help");
115 matPrint(canvas, 6, fontColorNV, "1/Q - increase/decrease scale");
116 }
117 else
118 {
119 matPrint(canvas, 2, fontColorNV, "H - toggle hotkeys help");
120 }
121 }
122
123
main(int argc,const char * argv[])124 int main(int argc, const char *argv[])
125 {
126 if (argc == 1)
127 {
128 help();
129 return -1;
130 }
131
132 if (getCudaEnabledDeviceCount() == 0)
133 {
134 return cerr << "No GPU found or the library is compiled without CUDA support" << endl, -1;
135 }
136
137 cv::cuda::printShortCudaDeviceInfo(cv::cuda::getDevice());
138
139 string cascadeName;
140 string inputName;
141 bool isInputImage = false;
142 bool isInputVideo = false;
143 bool isInputCamera = false;
144
145 for (int i = 1; i < argc; ++i)
146 {
147 if (string(argv[i]) == "--cascade")
148 cascadeName = argv[++i];
149 else if (string(argv[i]) == "--video")
150 {
151 inputName = argv[++i];
152 isInputVideo = true;
153 }
154 else if (string(argv[i]) == "--camera")
155 {
156 inputName = argv[++i];
157 isInputCamera = true;
158 }
159 else if (string(argv[i]) == "--help")
160 {
161 help();
162 return -1;
163 }
164 else if (!isInputImage)
165 {
166 inputName = argv[i];
167 isInputImage = true;
168 }
169 else
170 {
171 cout << "Unknown key: " << argv[i] << endl;
172 return -1;
173 }
174 }
175
176 Ptr<cuda::CascadeClassifier> cascade_gpu = cuda::CascadeClassifier::create(cascadeName);
177
178 cv::CascadeClassifier cascade_cpu;
179 if (!cascade_cpu.load(cascadeName))
180 {
181 return cerr << "ERROR: Could not load cascade classifier \"" << cascadeName << "\"" << endl, help(), -1;
182 }
183
184 VideoCapture capture;
185 Mat image;
186
187 if (isInputImage)
188 {
189 image = imread(inputName);
190 CV_Assert(!image.empty());
191 }
192 else if (isInputVideo)
193 {
194 capture.open(inputName);
195 CV_Assert(capture.isOpened());
196 }
197 else
198 {
199 capture.open(atoi(inputName.c_str()));
200 CV_Assert(capture.isOpened());
201 }
202
203 namedWindow("result", 1);
204
205 Mat frame, frame_cpu, gray_cpu, resized_cpu, frameDisp;
206 vector<Rect> faces;
207
208 GpuMat frame_gpu, gray_gpu, resized_gpu, facesBuf_gpu;
209
210 /* parameters */
211 bool useGPU = true;
212 double scaleFactor = 1.0;
213 bool findLargestObject = false;
214 bool filterRects = true;
215 bool helpScreen = false;
216
217 for (;;)
218 {
219 if (isInputCamera || isInputVideo)
220 {
221 capture >> frame;
222 if (frame.empty())
223 {
224 break;
225 }
226 }
227
228 (image.empty() ? frame : image).copyTo(frame_cpu);
229 frame_gpu.upload(image.empty() ? frame : image);
230
231 convertAndResize(frame_gpu, gray_gpu, resized_gpu, scaleFactor);
232 convertAndResize(frame_cpu, gray_cpu, resized_cpu, scaleFactor);
233
234 TickMeter tm;
235 tm.start();
236
237 if (useGPU)
238 {
239 cascade_gpu->setFindLargestObject(findLargestObject);
240 cascade_gpu->setScaleFactor(1.2);
241 cascade_gpu->setMinNeighbors((filterRects || findLargestObject) ? 4 : 0);
242
243 cascade_gpu->detectMultiScale(resized_gpu, facesBuf_gpu);
244 cascade_gpu->convert(facesBuf_gpu, faces);
245 }
246 else
247 {
248 Size minSize = cascade_gpu->getClassifierSize();
249 cascade_cpu.detectMultiScale(resized_cpu, faces, 1.2,
250 (filterRects || findLargestObject) ? 4 : 0,
251 (findLargestObject ? CASCADE_FIND_BIGGEST_OBJECT : 0)
252 | CASCADE_SCALE_IMAGE,
253 minSize);
254 }
255
256 for (size_t i = 0; i < faces.size(); ++i)
257 {
258 rectangle(resized_cpu, faces[i], Scalar(255));
259 }
260
261 tm.stop();
262 double detectionTime = tm.getTimeMilli();
263 double fps = 1000 / detectionTime;
264
265 //print detections to console
266 cout << setfill(' ') << setprecision(2);
267 cout << setw(6) << fixed << fps << " FPS, " << faces.size() << " det";
268 if ((filterRects || findLargestObject) && !faces.empty())
269 {
270 for (size_t i = 0; i < faces.size(); ++i)
271 {
272 cout << ", [" << setw(4) << faces[i].x
273 << ", " << setw(4) << faces[i].y
274 << ", " << setw(4) << faces[i].width
275 << ", " << setw(4) << faces[i].height << "]";
276 }
277 }
278 cout << endl;
279
280 cv::cvtColor(resized_cpu, frameDisp, COLOR_GRAY2BGR);
281 displayState(frameDisp, helpScreen, useGPU, findLargestObject, filterRects, fps);
282 imshow("result", frameDisp);
283
284 char key = (char)waitKey(5);
285 if (key == 27)
286 {
287 break;
288 }
289
290 switch (key)
291 {
292 case ' ':
293 useGPU = !useGPU;
294 break;
295 case 'm':
296 case 'M':
297 findLargestObject = !findLargestObject;
298 break;
299 case 'f':
300 case 'F':
301 filterRects = !filterRects;
302 break;
303 case '1':
304 scaleFactor *= 1.05;
305 break;
306 case 'q':
307 case 'Q':
308 scaleFactor /= 1.05;
309 break;
310 case 'h':
311 case 'H':
312 helpScreen = !helpScreen;
313 break;
314 }
315 }
316
317 return 0;
318 }
319