00001 #include <iostream>
00002 #include <fstream>
00003 #include <string>
00004 #include <sstream>
00005 #include <iomanip>
00006 #include <stdexcept>
00007 #include "opencv2/gpu/gpu.hpp"
00008 #include "opencv2/highgui/highgui.hpp"
00009
00010 using namespace std;
00011 using namespace cv;
00012
00013
00016 class Settings
00017 {
00018 public:
00020 Settings();
00021
00023 static Settings Read(int argc, char** argv);
00024
00025 string src;
00026 bool src_is_video;
00027 bool make_gray;
00028 bool resize_src;
00029 double resize_src_scale;
00030 double scale;
00031 int nlevels;
00032 int gr_threshold;
00033 double hit_threshold;
00034 int win_width;
00035 int win_stride_width;
00036 int win_stride_height;
00037 bool gamma_corr;
00038 };
00039
00040
00042 class App
00043 {
00044 public:
00046 App(const Settings& s);
00047
00049 void RunOpencvGui();
00050
00052 void HandleKey(char key);
00053
00054 void HogWorkBegin();
00055 void HogWorkEnd();
00056 double HogWorkFps() const;
00057
00058 void WorkBegin();
00059 void WorkEnd();
00060 double WorkFps() const;
00061
00062 const string GetPerformanceSummary() const;
00063
00064 private:
00065 App operator=(App&);
00066
00067 Settings settings;
00068 bool running;
00069
00070 bool use_gpu;
00071 bool make_gray;
00072 double scale;
00073 int gr_threshold;
00074 int nlevels;
00075 double hit_threshold;
00076 bool gamma_corr;
00077
00078 int64 hog_work_begin;
00079 double hog_work_fps;
00080
00081 int64 work_begin;
00082 double work_fps;
00083 };
00084
00085
00086 int main(int argc, char** argv)
00087 {
00088 try
00089 {
00090 if (argc < 2)
00091 {
00092 cout << "Usage:\nsample_hog\n"
00093 << " -src <path_to_the_source>\n"
00094 << " [-src_is_video <true/false>] # says to interp. src as img or as video\n"
00095 << " [-make_gray <true/false>] # convert image to gray one or not\n"
00096 << " [-resize_src <true/false>] # do resize of the source image or not\n"
00097 << " [-resize_src_scale <double>] # preprocessing image scale factor\n"
00098 << " [-hit_threshold <double>] # classifying plane dist. threshold (0.0 usually)\n"
00099 << " [-scale <double>] # HOG window scale factor\n"
00100 << " [-nlevels <int>] # max number of HOG window scales\n"
00101 << " [-win_width <int>] # width of the window (48 or 64)\n"
00102 << " [-win_stride_width <int>] # distance by OX axis between neighbour wins\n"
00103 << " [-win_stride_height <int>] # distance by OY axis between neighbour wins\n"
00104 << " [-gr_threshold <int>] # merging similar rects constant\n"
00105 << " [-gamma_corr <int>] # do gamma correction or not\n";
00106 return 1;
00107 }
00108 App app(Settings::Read(argc, argv));
00109 app.RunOpencvGui();
00110 }
00111 catch (const Exception& e) { return cout << "Error: " << e.what() << endl, 1; }
00112 catch (const exception& e) { return cout << "Error: " << e.what() << endl, 1; }
00113 catch(...) { return cout << "Unknown exception" << endl, 1; }
00114 return 0;
00115 }
00116
00117
00118 Settings::Settings()
00119 {
00120 src_is_video = false;
00121 make_gray = false;
00122 resize_src = true;
00123 resize_src_scale = 1.5;
00124 scale = 1.05;
00125 nlevels = 13;
00126 gr_threshold = 8;
00127 hit_threshold = 1.4;
00128 win_width = 48;
00129 win_stride_width = 8;
00130 win_stride_height = 8;
00131 gamma_corr = true;
00132 }
00133
00134
00135 Settings Settings::Read(int argc, char** argv)
00136 {
00137 cout << "Parsing command args" << endl;
00138
00139 Settings settings;
00140 for (int i = 1; i < argc - 1; i += 2)
00141 {
00142 string key = argv[i];
00143 string val = argv[i + 1];
00144 if (key == "-src") settings.src = val;
00145 else if (key == "-src_is_video") settings.src_is_video = (val == "true");
00146 else if (key == "-make_gray") settings.make_gray = (val == "true");
00147 else if (key == "-resize_src") settings.resize_src = (val == "true");
00148 else if (key == "-resize_src_scale") settings.resize_src_scale = atof(val.c_str());
00149 else if (key == "-hit_threshold") settings.hit_threshold = atof(val.c_str());
00150 else if (key == "-scale") settings.scale = atof(val.c_str());
00151 else if (key == "-nlevels") settings.nlevels = atoi(val.c_str());
00152 else if (key == "-win_width") settings.win_width = atoi(val.c_str());
00153 else if (key == "-win_stride_width") settings.win_stride_width = atoi(val.c_str());
00154 else if (key == "-win_stride_height") settings.win_stride_height = atoi(val.c_str());
00155 else if (key == "-gr_threshold") settings.gr_threshold = atoi(val.c_str());
00156 else if (key == "-gamma_corr") settings.gamma_corr = atoi(val.c_str()) != 0;
00157 else throw runtime_error((string("Unknown key: ") + key));
00158 }
00159
00160 cout << "Command args are parsed\n";
00161 return settings;
00162 }
00163
00164
00165 App::App(const Settings &s)
00166 {
00167 settings = s;
00168 cout << "\nControls:\n"
00169 << "\tESC - exit\n"
00170 << "\tm - change mode GPU <-> CPU\n"
00171 << "\tg - convert image to gray or not\n"
00172 << "\t1/q - increase/decrease HOG scale\n"
00173 << "\t2/w - increase/decrease levels count\n"
00174 << "\t3/e - increase/decrease HOG group threshold\n"
00175 << "\t4/r - increase/decrease hit threshold\n"
00176 << endl;
00177
00178 use_gpu = true;
00179 make_gray = settings.make_gray;
00180 scale = settings.scale;
00181 gr_threshold = settings.gr_threshold;
00182 nlevels = settings.nlevels;
00183 hit_threshold = settings.hit_threshold;
00184 gamma_corr = settings.gamma_corr;
00185
00186 if (settings.win_width != 64 && settings.win_width != 48)
00187 settings.win_width = 64;
00188
00189 cout << "Scale: " << scale << endl;
00190 cout << "Group threshold: " << gr_threshold << endl;
00191 cout << "Levels number: " << nlevels << endl;
00192 cout << "Win width: " << settings.win_width << endl;
00193 cout << "Win stride: (" << settings.win_stride_width << ", " << settings.win_stride_height << ")\n";
00194 cout << "Hit threshold: " << hit_threshold << endl;
00195 cout << "Gamma correction: " << gamma_corr << endl;
00196 cout << endl;
00197 }
00198
00199
00200 void App::RunOpencvGui()
00201 {
00202 running = true;
00203
00204 Size win_size(settings.win_width, settings.win_width * 2);
00205 Size win_stride(settings.win_stride_width, settings.win_stride_height);
00206
00207 vector<float> detector;
00208
00209 if (win_size == Size(64, 128))
00210 detector = cv::gpu::HOGDescriptor::getPeopleDetector_64x128();
00211 else
00212 detector = cv::gpu::HOGDescriptor::getPeopleDetector_48x96();
00213
00214
00215 cv::gpu::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9,
00216 cv::gpu::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr,
00217 cv::gpu::HOGDescriptor::DEFAULT_NLEVELS);
00218 gpu_hog.setSVMDetector(detector);
00219
00220
00221 cv::HOGDescriptor cpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9, 1, -1,
00222 HOGDescriptor::L2Hys, 0.2, gamma_corr, cv::HOGDescriptor::DEFAULT_NLEVELS);
00223 cpu_hog.setSVMDetector(detector);
00224
00225
00226 while (running)
00227 {
00228 VideoCapture vc;
00229 Mat frame;
00230
00231 if (settings.src_is_video)
00232 {
00233 vc.open(settings.src.c_str());
00234 if (!vc.isOpened())
00235 throw runtime_error(string("Can't open video file: " + settings.src));
00236 vc >> frame;
00237 }
00238 else
00239 {
00240 frame = imread(settings.src);
00241 if (frame.empty())
00242 throw runtime_error(string("Can't open image file: " + settings.src));
00243 }
00244
00245 Mat img_aux, img, img_to_show;
00246 gpu::GpuMat gpu_img;
00247
00248
00249 while (running && !frame.empty())
00250 {
00251 WorkBegin();
00252
00253 vector<Rect> found;
00254
00255
00256 if (make_gray)
00257 cvtColor(frame, img_aux, CV_BGR2GRAY);
00258 else if (use_gpu)
00259 cvtColor(frame, img_aux, CV_BGR2BGRA);
00260 else
00261 img_aux = frame;
00262
00263
00264 if (settings.resize_src)
00265 resize(img_aux, img, Size(int(frame.cols * settings.resize_src_scale), int(frame.rows * settings.resize_src_scale)));
00266 else
00267 img = img_aux;
00268 img_to_show = img;
00269
00270 gpu_hog.nlevels = nlevels;
00271 cpu_hog.nlevels = nlevels;
00272
00273
00274 HogWorkBegin();
00275 if (use_gpu)
00276 {
00277 gpu_img = img;
00278 gpu_hog.detectMultiScale(gpu_img, found, hit_threshold, win_stride, Size(0, 0), scale, gr_threshold);
00279 }
00280 else
00281 cpu_hog.detectMultiScale(img, found, hit_threshold, win_stride, Size(0, 0), scale, gr_threshold);
00282 HogWorkEnd();
00283
00284
00285 for (size_t i = 0; i < found.size(); i++)
00286 {
00287 Rect r = found[i];
00288 rectangle(img_to_show, r.tl(), r.br(), CV_RGB(0, 255, 0), 3);
00289 }
00290
00291 WorkEnd();
00292
00293
00294 putText(img_to_show, GetPerformanceSummary(), Point(5, 25), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2);
00295 imshow("opencv_gpu_hog", img_to_show);
00296 HandleKey((char)waitKey(3));
00297
00298 if (settings.src_is_video)
00299 {
00300 vc >> frame;
00301 }
00302 }
00303 }
00304 }
00305
00306
00307 void App::HandleKey(char key)
00308 {
00309 switch (key)
00310 {
00311 case 27:
00312 running = false;
00313 break;
00314 case 'm':
00315 case 'M':
00316 use_gpu = !use_gpu;
00317 cout << "Switched to " << (use_gpu ? "CUDA" : "CPU") << " mode\n";
00318 break;
00319 case 'g':
00320 case 'G':
00321 make_gray = !make_gray;
00322 cout << "Convert image to gray: " << (make_gray ? "YES" : "NO") << endl;
00323 break;
00324 case '1':
00325 scale *= 1.05;
00326 cout << "Scale: " << scale << endl;
00327 break;
00328 case 'q':
00329 case 'Q':
00330 scale /= 1.05;
00331 cout << "Scale: " << scale << endl;
00332 break;
00333 case '2':
00334 nlevels++;
00335 cout << "Levels number: " << nlevels << endl;
00336 break;
00337 case 'w':
00338 case 'W':
00339 nlevels = max(nlevels - 1, 1);
00340 cout << "Levels number: " << nlevels << endl;
00341 break;
00342 case '3':
00343 gr_threshold++;
00344 cout << "Group threshold: " << gr_threshold << endl;
00345 break;
00346 case 'e':
00347 case 'E':
00348 gr_threshold = max(0, gr_threshold - 1);
00349 cout << "Group threshold: " << gr_threshold << endl;
00350 break;
00351 case '4':
00352 hit_threshold+=0.25;
00353 cout << "Hit threshold: " << hit_threshold << endl;
00354 break;
00355 case 'r':
00356 case 'R':
00357 hit_threshold = max(0.0, hit_threshold - 0.25);
00358 cout << "Hit threshold: " << hit_threshold << endl;
00359 break;
00360 case 'c':
00361 case 'C':
00362 gamma_corr = !gamma_corr;
00363 cout << "Gamma correction: " << gamma_corr << endl;
00364 break;
00365 }
00366 }
00367
00368
00369 inline void App::HogWorkBegin() { hog_work_begin = getTickCount(); }
00370
00371
00372 inline void App::HogWorkEnd()
00373 {
00374 int64 delta = getTickCount() - hog_work_begin;
00375 double freq = getTickFrequency();
00376 hog_work_fps = freq / delta;
00377 }
00378
00379
00380 inline double App::HogWorkFps() const { return hog_work_fps; }
00381
00382
00383 inline void App::WorkBegin() { work_begin = getTickCount(); }
00384
00385
00386 inline void App::WorkEnd()
00387 {
00388 int64 delta = getTickCount() - work_begin;
00389 double freq = getTickFrequency();
00390 work_fps = freq / delta;
00391 }
00392
00393
00394 inline double App::WorkFps() const { return work_fps; }
00395
00396
00397 inline const string App::GetPerformanceSummary() const
00398 {
00399 stringstream ss;
00400 ss << (use_gpu ? "GPU" : "CPU") << " HOG FPS: " << setiosflags(ios::left) << setprecision(4) <<
00401 setw(7) << HogWorkFps() << " Total FPS: " << setprecision(4) << setw(7) << WorkFps();
00402 return ss.str();
00403 }