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