barcode.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #include <iostream>
  2. #include "opencv2/barcode.hpp"
  3. #include "opencv2/imgproc.hpp"
  4. #include "opencv2/highgui.hpp"
  5. using namespace cv;
  6. using namespace std;
  7. static int liveBarCodeDetect();
  8. static int imageBarCodeDetect(const string &in_file);
  9. static bool g_detectOnly = false;
  10. static string g_out_file_name, g_out_file_ext;
  11. static Ptr<barcode::BarcodeDetector> bardet;
  12. int main(int argc, char **argv)
  13. {
  14. const string keys = "{h help ? | | print help messages }"
  15. "{i in | | input image path (also switches to image detection mode) }"
  16. "{detect | false | detect 1D barcode only (skip decoding) }"
  17. "{o out | | path to result file (only for single image decode) }"
  18. "{sr_prototxt| | super resolution prototxt path }"
  19. "{sr_model | | super resolution model path }";
  20. CommandLineParser cmd_parser(argc, argv, keys);
  21. cmd_parser.about("This program detects the 1D barcodes from camera or images using the OpenCV library.");
  22. if (cmd_parser.has("help"))
  23. {
  24. cmd_parser.printMessage();
  25. return 0;
  26. }
  27. string in_file_name = cmd_parser.get<string>("in"); // path to input image
  28. string sr_prototxt = cmd_parser.get<string>("sr_prototxt"); // path to sr_prototxt
  29. string sr_model = cmd_parser.get<string>("sr_model"); // path to sr_model
  30. if (cmd_parser.has("out"))
  31. {
  32. std::string fpath = cmd_parser.get<string>("out"); // path to output image
  33. std::string::size_type idx = fpath.rfind('.');
  34. if (idx != std::string::npos)
  35. {
  36. g_out_file_name = fpath.substr(0, idx);
  37. g_out_file_ext = fpath.substr(idx);
  38. }
  39. else
  40. {
  41. g_out_file_name = fpath;
  42. g_out_file_ext = ".png";
  43. }
  44. }
  45. if (!cmd_parser.check())
  46. {
  47. cmd_parser.printErrors();
  48. return -1;
  49. }
  50. g_detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
  51. //! [initialize]
  52. try{
  53. bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model);
  54. } catch (const std::exception& e)
  55. {
  56. cout <<
  57. "\n---------------------------------------------------------------\n"
  58. "Failed to initialize super resolution.\n"
  59. "Please, download 'sr.*' from\n"
  60. "https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
  61. "and put them into the current directory.\n"
  62. "Or you can leave sr_prototxt and sr_model unspecified.\n"
  63. "---------------------------------------------------------------\n";
  64. cout << e.what() << endl;
  65. return -1;
  66. }
  67. //! [initialize]
  68. int return_code;
  69. if (in_file_name.empty())
  70. {
  71. return_code = liveBarCodeDetect();
  72. }
  73. else
  74. {
  75. return_code = imageBarCodeDetect(in_file_name);
  76. }
  77. return return_code;
  78. }
  79. static void drawBarcodeContour(Mat &color_image, const vector<Point> &corners, bool decodable)
  80. {
  81. if (!corners.empty())
  82. {
  83. double show_radius = (color_image.rows > color_image.cols) ? (2.813 * color_image.rows) / color_image.cols :
  84. (2.813 * color_image.cols) / color_image.rows;
  85. double contour_radius = show_radius * 0.4;
  86. vector<vector<Point> > contours;
  87. contours.push_back(corners);
  88. drawContours(color_image, contours, 0, decodable ? Scalar(0, 255, 0) : Scalar(0, 0, 255),
  89. cvRound(contour_radius));
  90. RNG rng(1000);
  91. for (size_t i = 0; i < 4; i++)
  92. {
  93. Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
  94. circle(color_image, corners[i], cvRound(show_radius), color, -1);
  95. }
  96. }
  97. }
  98. //! [visualize]
  99. static void drawFPS(Mat &color_image, double fps)
  100. {
  101. ostringstream convert;
  102. convert << cv::format("%.2f", fps) << " FPS (" << (g_detectOnly ? " detector" : " decoder") << ")";
  103. putText(color_image, convert.str(), Point(25, 25), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 255), 2);
  104. }
  105. static void drawBarcodeResults(Mat &frame, const vector<Point> &corners, const vector<cv::String> &decode_info,
  106. const vector<cv::barcode::BarcodeType> &decode_type, double fps)
  107. {
  108. if (!corners.empty())
  109. {
  110. for (size_t i = 0; i < corners.size(); i += 4)
  111. {
  112. size_t bar_idx = i / 4;
  113. vector<Point> barcode_contour(corners.begin() + i, corners.begin() + i + 4);
  114. drawBarcodeContour(frame, barcode_contour, g_detectOnly || decode_type[bar_idx] != barcode::NONE);
  115. cout << "BAR[" << bar_idx << "] @ " << Mat(barcode_contour).reshape(2, 1) << ": ";
  116. if (decode_info.size() > bar_idx)
  117. {
  118. if (!decode_info[bar_idx].empty())
  119. {
  120. cout << "TYPE: " << decode_type[bar_idx] << " INFO: " << decode_info[bar_idx] << endl;
  121. }
  122. else
  123. {
  124. cout << "can't decode 1D barcode" << endl;
  125. }
  126. }
  127. else
  128. {
  129. cout << "decode information is not available (disabled)" << endl;
  130. }
  131. }
  132. }
  133. else
  134. {
  135. cout << "Barcode is not detected" << endl;
  136. }
  137. drawFPS(frame, fps);
  138. }
  139. //! [visualize]
  140. static void
  141. runBarcode(const Mat &input, vector<Point> &corners, vector<cv::String> &decode_info,
  142. vector<cv::barcode::BarcodeType> &decode_type
  143. )
  144. {
  145. if (!g_detectOnly)
  146. {
  147. //! [detectAndDecode]
  148. bool result_detection = bardet->detectAndDecode(input, decode_info, decode_type, corners);
  149. //! [detectAndDecode]
  150. CV_UNUSED(result_detection);
  151. }
  152. else
  153. {
  154. //! [detect]
  155. bool result_detection = bardet->detect(input, corners);
  156. //! [detect]
  157. CV_UNUSED(result_detection);
  158. }
  159. }
  160. int liveBarCodeDetect()
  161. {
  162. VideoCapture cap(0);
  163. if (!cap.isOpened())
  164. {
  165. cout << "Cannot open a camera" << endl;
  166. return 2;
  167. }
  168. cout << "Press 'd' to switch between decoder and detector" << endl;
  169. cout << "Press 'ESC' to exit" << endl;
  170. for (;;)
  171. {
  172. Mat frame;
  173. cap >> frame;
  174. if (frame.empty())
  175. {
  176. cout << "End of video stream" << endl;
  177. break;
  178. }
  179. Mat result;
  180. if (frame.channels() == 1)
  181. {
  182. cvtColor(frame, result, COLOR_GRAY2BGR);
  183. }
  184. else
  185. {
  186. frame.copyTo(result);
  187. }
  188. TickMeter timer;
  189. //! [output]
  190. vector<cv::String> decode_info;
  191. vector<barcode::BarcodeType> decoded_type;
  192. vector<Point> corners;
  193. //! [output]
  194. timer.start();
  195. runBarcode(frame, corners, decode_info, decoded_type);
  196. timer.stop();
  197. double fps = 1 / timer.getTimeSec();
  198. drawBarcodeResults(result, corners, decode_info, decoded_type, fps);
  199. if (!result.empty())
  200. {
  201. imshow("barcode", result);
  202. }
  203. int code = waitKey(1);
  204. if (code < 0)
  205. {
  206. continue;
  207. } // timeout
  208. char c = (char) code;
  209. if (c == 'd')
  210. {
  211. g_detectOnly = !g_detectOnly;
  212. cout << "Switching barcode decoder mode ==> " << (g_detectOnly ? "detect" : "decode") << endl;
  213. }
  214. if (c == 27)
  215. {
  216. cout << "'ESC' is pressed. Exiting..." << endl;
  217. break;
  218. }
  219. }
  220. cout << "Exit." << endl;
  221. return 0;
  222. }
  223. int imageBarCodeDetect(const string &in_file)
  224. {
  225. const int count_experiments = 10;
  226. Mat input = imread(in_file, IMREAD_COLOR);
  227. cout << "Run BarCode" << (g_detectOnly ? " detector" : " decoder") << " on image: " << input.size() << " ("
  228. << typeToString(input.type()) << ")" << endl;
  229. vector<Point> corners;
  230. vector<cv::String> decode_info;
  231. vector<barcode::BarcodeType> decoded_type;
  232. TickMeter timer;
  233. for (size_t i = 0; i < count_experiments; i++)
  234. {
  235. corners.clear();
  236. decode_info.clear();
  237. timer.start();
  238. runBarcode(input, corners, decode_info, decoded_type);
  239. timer.stop();
  240. }
  241. double fps = count_experiments / timer.getTimeSec();
  242. cout << "FPS: " << fps << endl;
  243. Mat result;
  244. input.copyTo(result);
  245. drawBarcodeResults(result, corners, decode_info, decoded_type, fps);
  246. if (!g_out_file_name.empty())
  247. {
  248. string out_file = g_out_file_name + g_out_file_ext;
  249. cout << "Saving result: " << out_file << endl;
  250. imwrite(out_file, result);
  251. }
  252. imshow("barcode", result);
  253. waitKey(1);
  254. cout << "Press any key to exit ..." << endl;
  255. waitKey(0);
  256. cout << "Exit." << endl;
  257. return 0;
  258. }