barcode.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include <iostream>
  2. #include "opencv2/objdetect.hpp"
  3. #include "opencv2/imgproc.hpp"
  4. #include "opencv2/highgui.hpp"
  5. using namespace cv;
  6. using namespace std;
  7. static const Scalar greenColor(0, 255, 0);
  8. static const Scalar redColor(0, 0, 255);
  9. static const Scalar yellowColor(0, 255, 255);
  10. static Scalar randColor()
  11. {
  12. RNG &rng = theRNG();
  13. return Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
  14. }
  15. //==============================================================================
  16. struct TheApp
  17. {
  18. Ptr<barcode::BarcodeDetector> bardet;
  19. //! [output]
  20. vector<Point> corners;
  21. vector<string> decode_info;
  22. vector<string> decode_type;
  23. //! [output]
  24. bool detectOnly;
  25. void cleanup()
  26. {
  27. corners.clear();
  28. decode_info.clear();
  29. decode_type.clear();
  30. }
  31. inline string modeString() const
  32. {
  33. return detectOnly ? "<detect>" : "<detectAndDecode>";
  34. }
  35. void drawResults(Mat &frame) const
  36. {
  37. //! [visualize]
  38. for (size_t i = 0; i < corners.size(); i += 4)
  39. {
  40. const size_t idx = i / 4;
  41. const bool isDecodable = idx < decode_info.size()
  42. && idx < decode_type.size()
  43. && !decode_type[idx].empty();
  44. const Scalar lineColor = isDecodable ? greenColor : redColor;
  45. // draw barcode rectangle
  46. vector<Point> contour(corners.begin() + i, corners.begin() + i + 4);
  47. const vector< vector<Point> > contours {contour};
  48. drawContours(frame, contours, 0, lineColor, 1);
  49. // draw vertices
  50. for (size_t j = 0; j < 4; j++)
  51. circle(frame, contour[j], 2, randColor(), -1);
  52. // write decoded text
  53. if (isDecodable)
  54. {
  55. ostringstream buf;
  56. buf << "[" << decode_type[idx] << "] " << decode_info[idx];
  57. putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1);
  58. }
  59. }
  60. //! [visualize]
  61. }
  62. void drawFPS(Mat &frame, double fps) const
  63. {
  64. ostringstream buf;
  65. buf << modeString()
  66. << " (" << corners.size() / 4 << "/" << decode_type.size() << "/" << decode_info.size() << ") "
  67. << cv::format("%.2f", fps) << " FPS ";
  68. putText(frame, buf.str(), Point(25, 25), FONT_HERSHEY_COMPLEX, 0.8, redColor, 2);
  69. }
  70. inline void call_decode(Mat &frame)
  71. {
  72. cleanup();
  73. if (detectOnly)
  74. {
  75. //! [detect]
  76. bardet->detectMulti(frame, corners);
  77. //! [detect]
  78. }
  79. else
  80. {
  81. //! [detectAndDecode]
  82. bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners);
  83. //! [detectAndDecode]
  84. }
  85. }
  86. int liveBarCodeDetect()
  87. {
  88. VideoCapture cap(0);
  89. if (!cap.isOpened())
  90. {
  91. cout << "Cannot open a camera" << endl;
  92. return 2;
  93. }
  94. Mat frame;
  95. Mat result;
  96. cap >> frame;
  97. cout << "Image size: " << frame.size() << endl;
  98. cout << "Press 'd' to switch between <detect> and <detectAndDecode> modes" << endl;
  99. cout << "Press 'ESC' to exit" << endl;
  100. for (;;)
  101. {
  102. cap >> frame;
  103. if (frame.empty())
  104. {
  105. cout << "End of video stream" << endl;
  106. break;
  107. }
  108. if (frame.channels() == 1)
  109. cvtColor(frame, frame, COLOR_GRAY2BGR);
  110. TickMeter timer;
  111. timer.start();
  112. call_decode(frame);
  113. timer.stop();
  114. drawResults(frame);
  115. drawFPS(frame, timer.getFPS());
  116. imshow("barcode", frame);
  117. const char c = (char)waitKey(1);
  118. if (c == 'd')
  119. {
  120. detectOnly = !detectOnly;
  121. cout << "Mode switched to " << modeString() << endl;
  122. }
  123. else if (c == 27)
  124. {
  125. cout << "'ESC' is pressed. Exiting..." << endl;
  126. break;
  127. }
  128. }
  129. return 0;
  130. }
  131. int imageBarCodeDetect(const string &in_file, const string &out_file)
  132. {
  133. Mat frame = imread(in_file, IMREAD_COLOR);
  134. cout << "Image size: " << frame.size() << endl;
  135. cout << "Mode is " << modeString() << endl;
  136. const int count_experiments = 100;
  137. TickMeter timer;
  138. for (size_t i = 0; i < count_experiments; i++)
  139. {
  140. timer.start();
  141. call_decode(frame);
  142. timer.stop();
  143. }
  144. cout << "FPS: " << timer.getFPS() << endl;
  145. drawResults(frame);
  146. if (!out_file.empty())
  147. {
  148. cout << "Saving result: " << out_file << endl;
  149. imwrite(out_file, frame);
  150. }
  151. imshow("barcode", frame);
  152. cout << "Press any key to exit ..." << endl;
  153. waitKey(0);
  154. return 0;
  155. }
  156. };
  157. //==============================================================================
  158. int main(int argc, char **argv)
  159. {
  160. const string keys = "{h help ? | | print help messages }"
  161. "{i in | | input image path (also switches to image detection mode) }"
  162. "{detect | false | detect 1D barcode only (skip decoding) }"
  163. "{o out | | path to result file (only for single image decode) }"
  164. "{sr_prototxt| | super resolution prototxt path }"
  165. "{sr_model | | super resolution model path }";
  166. CommandLineParser cmd_parser(argc, argv, keys);
  167. cmd_parser.about("This program detects the 1D barcodes from camera or images using the OpenCV library.");
  168. if (cmd_parser.has("help"))
  169. {
  170. cmd_parser.printMessage();
  171. return 0;
  172. }
  173. const string in_file = cmd_parser.get<string>("in");
  174. const string out_file = cmd_parser.get<string>("out");
  175. const string sr_prototxt = cmd_parser.get<string>("sr_prototxt");
  176. const string sr_model = cmd_parser.get<string>("sr_model");
  177. if (!cmd_parser.check())
  178. {
  179. cmd_parser.printErrors();
  180. return -1;
  181. }
  182. TheApp app;
  183. app.detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
  184. //! [initialize]
  185. try
  186. {
  187. app.bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model);
  188. }
  189. catch (const std::exception& e)
  190. {
  191. cout <<
  192. "\n---------------------------------------------------------------\n"
  193. "Failed to initialize super resolution.\n"
  194. "Please, download 'sr.*' from\n"
  195. "https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
  196. "and put them into the current directory.\n"
  197. "Or you can leave sr_prototxt and sr_model unspecified.\n"
  198. "---------------------------------------------------------------\n";
  199. cout << e.what() << endl;
  200. return -1;
  201. }
  202. //! [initialize]
  203. if (in_file.empty())
  204. return app.liveBarCodeDetect();
  205. else
  206. return app.imageBarCodeDetect(in_file, out_file);
  207. }