hog.cpp 9.6 KB

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