• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include <sstream>
5 #include <iomanip>
6 #include <stdexcept>
7 #include <opencv2/core/ocl.hpp>
8 #include <opencv2/core/utility.hpp>
9 #include "opencv2/imgcodecs.hpp"
10 #include <opencv2/video.hpp>
11 #include <opencv2/videoio.hpp>
12 #include <opencv2/highgui.hpp>
13 #include <opencv2/objdetect.hpp>
14 #include <opencv2/imgproc.hpp>
15 
16 using namespace std;
17 using namespace cv;
18 
19 class App
20 {
21 public:
22     App(CommandLineParser& cmd);
23     void run();
24     void handleKey(char key);
25     void hogWorkBegin();
26     void hogWorkEnd();
27     string hogWorkFps() const;
28     void workBegin();
29     void workEnd();
30     string workFps() const;
31     string message() const;
32 
33 
34 // This function test if gpu_rst matches cpu_rst.
35 // If the two vectors are not equal, it will return the difference in vector size
36 // Else if will return
37 // (total diff of each cpu and gpu rects covered pixels)/(total cpu rects covered pixels)
38     double checkRectSimilarity(Size sz,
39                                std::vector<Rect>& cpu_rst,
40                                std::vector<Rect>& gpu_rst);
41 private:
42     App operator=(App&);
43 
44     //Args args;
45     bool running;
46     bool make_gray;
47     double scale;
48     double resize_scale;
49     int win_width;
50     int win_stride_width, win_stride_height;
51     int gr_threshold;
52     int nlevels;
53     double hit_threshold;
54     bool gamma_corr;
55 
56     int64 hog_work_begin;
57     double hog_work_fps;
58     int64 work_begin;
59     double work_fps;
60 
61     string img_source;
62     string vdo_source;
63     string output;
64     int camera_id;
65     bool write_once;
66 };
67 
main(int argc,char ** argv)68 int main(int argc, char** argv)
69 {
70     const char* keys =
71         "{ h help      | false          | print help message }"
72         "{ i input     |                | specify input image}"
73         "{ c camera    | -1             | enable camera capturing }"
74         "{ v video     | ../data/768x576.avi | use video as input }"
75         "{ g gray      | false          | convert image to gray one or not}"
76         "{ s scale     | 1.0            | resize the image before detect}"
77         "{ o output    |                | specify output path when input is images}";
78     CommandLineParser cmd(argc, argv, keys);
79     if (cmd.has("help"))
80     {
81         cout << "Usage : hog [options]" << endl;
82         cout << "Available options:" << endl;
83         cmd.printMessage();
84         return EXIT_SUCCESS;
85     }
86 
87     App app(cmd);
88     try
89     {
90         app.run();
91     }
92     catch (const Exception& e)
93     {
94         return cout << "error: "  << e.what() << endl, 1;
95     }
96     catch (const exception& e)
97     {
98         return cout << "error: "  << e.what() << endl, 1;
99     }
100     catch(...)
101     {
102         return cout << "unknown exception" << endl, 1;
103     }
104     return EXIT_SUCCESS;
105 }
106 
App(CommandLineParser & cmd)107 App::App(CommandLineParser& cmd)
108 {
109     cout << "\nControls:\n"
110          << "\tESC - exit\n"
111          << "\tm - change mode GPU <-> CPU\n"
112          << "\tg - convert image to gray or not\n"
113          << "\to - save output image once, or switch on/off video save\n"
114          << "\t1/q - increase/decrease HOG scale\n"
115          << "\t2/w - increase/decrease levels count\n"
116          << "\t3/e - increase/decrease HOG group threshold\n"
117          << "\t4/r - increase/decrease hit threshold\n"
118          << endl;
119 
120     make_gray = cmd.has("gray");
121     resize_scale = cmd.get<double>("s");
122     vdo_source = cmd.get<string>("v");
123     img_source = cmd.get<string>("i");
124     output = cmd.get<string>("o");
125     camera_id = cmd.get<int>("c");
126 
127     win_width = 48;
128     win_stride_width = 8;
129     win_stride_height = 8;
130     gr_threshold = 8;
131     nlevels = 13;
132     hit_threshold = 1.4;
133     scale = 1.05;
134     gamma_corr = true;
135     write_once = false;
136 
137     cout << "Group threshold: " << gr_threshold << endl;
138     cout << "Levels number: " << nlevels << endl;
139     cout << "Win width: " << win_width << endl;
140     cout << "Win stride: (" << win_stride_width << ", " << win_stride_height << ")\n";
141     cout << "Hit threshold: " << hit_threshold << endl;
142     cout << "Gamma correction: " << gamma_corr << endl;
143     cout << endl;
144 }
145 
run()146 void App::run()
147 {
148     running = true;
149     VideoWriter video_writer;
150 
151     Size win_size(win_width, win_width * 2);
152     Size win_stride(win_stride_width, win_stride_height);
153 
154     // Create HOG descriptors and detectors here
155 
156     HOGDescriptor hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1,
157                           HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS);
158     hog.setSVMDetector( HOGDescriptor::getDaimlerPeopleDetector() );
159 
160     while (running)
161     {
162         VideoCapture vc;
163         UMat frame;
164 
165         if (vdo_source!="")
166         {
167             vc.open(vdo_source.c_str());
168             if (!vc.isOpened())
169                 throw runtime_error(string("can't open video file: " + vdo_source));
170             vc >> frame;
171         }
172         else if (camera_id != -1)
173         {
174             vc.open(camera_id);
175             if (!vc.isOpened())
176             {
177                 stringstream msg;
178                 msg << "can't open camera: " << camera_id;
179                 throw runtime_error(msg.str());
180             }
181             vc >> frame;
182         }
183         else
184         {
185             imread(img_source).copyTo(frame);
186             if (frame.empty())
187                 throw runtime_error(string("can't open image file: " + img_source));
188         }
189 
190         UMat img_aux, img;
191         Mat img_to_show;
192 
193         // Iterate over all frames
194         while (running && !frame.empty())
195         {
196             workBegin();
197 
198             // Change format of the image
199             if (make_gray) cvtColor(frame, img_aux, COLOR_BGR2GRAY );
200             else frame.copyTo(img_aux);
201 
202             // Resize image
203             if (abs(scale-1.0)>0.001)
204             {
205                 Size sz((int)((double)img_aux.cols/resize_scale), (int)((double)img_aux.rows/resize_scale));
206                 resize(img_aux, img, sz);
207             }
208             else img = img_aux;
209             img.copyTo(img_to_show);
210             hog.nlevels = nlevels;
211             vector<Rect> found;
212 
213             // Perform HOG classification
214             hogWorkBegin();
215 
216             hog.detectMultiScale(img, found, hit_threshold, win_stride,
217                     Size(0, 0), scale, gr_threshold);
218             hogWorkEnd();
219 
220 
221             // Draw positive classified windows
222             for (size_t i = 0; i < found.size(); i++)
223             {
224                 Rect r = found[i];
225                 rectangle(img_to_show, r.tl(), r.br(), Scalar(0, 255, 0), 3);
226             }
227 
228             putText(img_to_show, ocl::useOpenCL() ? "Mode: OpenCL"  : "Mode: CPU", Point(5, 25), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
229             putText(img_to_show, "FPS (HOG only): " + hogWorkFps(), Point(5, 65), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
230             putText(img_to_show, "FPS (total): " + workFps(), Point(5, 105), FONT_HERSHEY_SIMPLEX, 1., Scalar(255, 100, 0), 2);
231             imshow("opencv_hog", img_to_show);
232             if (vdo_source!="" || camera_id!=-1) vc >> frame;
233 
234             workEnd();
235 
236             if (output!="" && write_once)
237             {
238                 if (img_source!="")     // wirte image
239                 {
240                     write_once = false;
241                     imwrite(output, img_to_show);
242                 }
243                 else                    //write video
244                 {
245                     if (!video_writer.isOpened())
246                     {
247                         video_writer.open(output, VideoWriter::fourcc('x','v','i','d'), 24,
248                                           img_to_show.size(), true);
249                         if (!video_writer.isOpened())
250                             throw std::runtime_error("can't create video writer");
251                     }
252 
253                     if (make_gray) cvtColor(img_to_show, img, COLOR_GRAY2BGR);
254                     else cvtColor(img_to_show, img, COLOR_BGRA2BGR);
255 
256                     video_writer << img.getMat(ACCESS_READ);
257                 }
258             }
259 
260             handleKey((char)waitKey(3));
261         }
262     }
263 }
264 
handleKey(char key)265 void App::handleKey(char key)
266 {
267     switch (key)
268     {
269     case 27:
270         running = false;
271         break;
272     case 'm':
273     case 'M':
274         ocl::setUseOpenCL(!cv::ocl::useOpenCL());
275         cout << "Switched to " << (ocl::useOpenCL() ? "OpenCL enabled" : "CPU") << " mode\n";
276         break;
277     case 'g':
278     case 'G':
279         make_gray = !make_gray;
280         cout << "Convert image to gray: " << (make_gray ? "YES" : "NO") << endl;
281         break;
282     case '1':
283         scale *= 1.05;
284         cout << "Scale: " << scale << endl;
285         break;
286     case 'q':
287     case 'Q':
288         scale /= 1.05;
289         cout << "Scale: " << scale << endl;
290         break;
291     case '2':
292         nlevels++;
293         cout << "Levels number: " << nlevels << endl;
294         break;
295     case 'w':
296     case 'W':
297         nlevels = max(nlevels - 1, 1);
298         cout << "Levels number: " << nlevels << endl;
299         break;
300     case '3':
301         gr_threshold++;
302         cout << "Group threshold: " << gr_threshold << endl;
303         break;
304     case 'e':
305     case 'E':
306         gr_threshold = max(0, gr_threshold - 1);
307         cout << "Group threshold: " << gr_threshold << endl;
308         break;
309     case '4':
310         hit_threshold+=0.25;
311         cout << "Hit threshold: " << hit_threshold << endl;
312         break;
313     case 'r':
314     case 'R':
315         hit_threshold = max(0.0, hit_threshold - 0.25);
316         cout << "Hit threshold: " << hit_threshold << endl;
317         break;
318     case 'c':
319     case 'C':
320         gamma_corr = !gamma_corr;
321         cout << "Gamma correction: " << gamma_corr << endl;
322         break;
323     case 'o':
324     case 'O':
325         write_once = !write_once;
326         break;
327     }
328 }
329 
330 
hogWorkBegin()331 inline void App::hogWorkBegin()
332 {
333     hog_work_begin = getTickCount();
334 }
335 
hogWorkEnd()336 inline void App::hogWorkEnd()
337 {
338     int64 delta = getTickCount() - hog_work_begin;
339     double freq = getTickFrequency();
340     hog_work_fps = freq / delta;
341 }
342 
hogWorkFps() const343 inline string App::hogWorkFps() const
344 {
345     stringstream ss;
346     ss << hog_work_fps;
347     return ss.str();
348 }
349 
workBegin()350 inline void App::workBegin()
351 {
352     work_begin = getTickCount();
353 }
354 
workEnd()355 inline void App::workEnd()
356 {
357     int64 delta = getTickCount() - work_begin;
358     double freq = getTickFrequency();
359     work_fps = freq / delta;
360 }
361 
workFps() const362 inline string App::workFps() const
363 {
364     stringstream ss;
365     ss << work_fps;
366     return ss.str();
367 }
368