Home | History | Annotate | Download | only in tapi
      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 
     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 
    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 
    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 
    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 
    331 inline void App::hogWorkBegin()
    332 {
    333     hog_work_begin = getTickCount();
    334 }
    335 
    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 
    343 inline string App::hogWorkFps() const
    344 {
    345     stringstream ss;
    346     ss << hog_work_fps;
    347     return ss.str();
    348 }
    349 
    350 inline void App::workBegin()
    351 {
    352     work_begin = getTickCount();
    353 }
    354 
    355 inline void App::workEnd()
    356 {
    357     int64 delta = getTickCount() - work_begin;
    358     double freq = getTickFrequency();
    359     work_fps = freq / delta;
    360 }
    361 
    362 inline string App::workFps() const
    363 {
    364     stringstream ss;
    365     ss << work_fps;
    366     return ss.str();
    367 }
    368