• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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