samples/hog_tapi.cpp#

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