123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #include <iostream>
- #include "opencv2/barcode.hpp"
- #include "opencv2/imgproc.hpp"
- #include "opencv2/highgui.hpp"
- using namespace cv;
- using namespace std;
- static int liveBarCodeDetect();
- static int imageBarCodeDetect(const string &in_file);
- static bool g_detectOnly = false;
- static string g_out_file_name, g_out_file_ext;
- static Ptr<barcode::BarcodeDetector> bardet;
- int main(int argc, char **argv)
- {
- const string keys = "{h help ? | | print help messages }"
- "{i in | | input image path (also switches to image detection mode) }"
- "{detect | false | detect 1D barcode only (skip decoding) }"
- "{o out | | path to result file (only for single image decode) }"
- "{sr_prototxt| | super resolution prototxt path }"
- "{sr_model | | super resolution model path }";
- CommandLineParser cmd_parser(argc, argv, keys);
- cmd_parser.about("This program detects the 1D barcodes from camera or images using the OpenCV library.");
- if (cmd_parser.has("help"))
- {
- cmd_parser.printMessage();
- return 0;
- }
- string in_file_name = cmd_parser.get<string>("in"); // path to input image
- string sr_prototxt = cmd_parser.get<string>("sr_prototxt"); // path to sr_prototxt
- string sr_model = cmd_parser.get<string>("sr_model"); // path to sr_model
- if (cmd_parser.has("out"))
- {
- std::string fpath = cmd_parser.get<string>("out"); // path to output image
- std::string::size_type idx = fpath.rfind('.');
- if (idx != std::string::npos)
- {
- g_out_file_name = fpath.substr(0, idx);
- g_out_file_ext = fpath.substr(idx);
- }
- else
- {
- g_out_file_name = fpath;
- g_out_file_ext = ".png";
- }
- }
- if (!cmd_parser.check())
- {
- cmd_parser.printErrors();
- return -1;
- }
- g_detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
- //! [initialize]
- try{
- bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model);
- } catch (const std::exception& e)
- {
- cout <<
- "\n---------------------------------------------------------------\n"
- "Failed to initialize super resolution.\n"
- "Please, download 'sr.*' from\n"
- "https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
- "and put them into the current directory.\n"
- "Or you can leave sr_prototxt and sr_model unspecified.\n"
- "---------------------------------------------------------------\n";
- cout << e.what() << endl;
- return -1;
- }
- //! [initialize]
- int return_code;
- if (in_file_name.empty())
- {
- return_code = liveBarCodeDetect();
- }
- else
- {
- return_code = imageBarCodeDetect(in_file_name);
- }
- return return_code;
- }
- static void drawBarcodeContour(Mat &color_image, const vector<Point> &corners, bool decodable)
- {
- if (!corners.empty())
- {
- double show_radius = (color_image.rows > color_image.cols) ? (2.813 * color_image.rows) / color_image.cols :
- (2.813 * color_image.cols) / color_image.rows;
- double contour_radius = show_radius * 0.4;
- vector<vector<Point> > contours;
- contours.push_back(corners);
- drawContours(color_image, contours, 0, decodable ? Scalar(0, 255, 0) : Scalar(0, 0, 255),
- cvRound(contour_radius));
- RNG rng(1000);
- for (size_t i = 0; i < 4; i++)
- {
- Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
- circle(color_image, corners[i], cvRound(show_radius), color, -1);
- }
- }
- }
- //! [visualize]
- static void drawFPS(Mat &color_image, double fps)
- {
- ostringstream convert;
- convert << cv::format("%.2f", fps) << " FPS (" << (g_detectOnly ? " detector" : " decoder") << ")";
- putText(color_image, convert.str(), Point(25, 25), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 255), 2);
- }
- static void drawBarcodeResults(Mat &frame, const vector<Point> &corners, const vector<cv::String> &decode_info,
- const vector<cv::barcode::BarcodeType> &decode_type, double fps)
- {
- if (!corners.empty())
- {
- for (size_t i = 0; i < corners.size(); i += 4)
- {
- size_t bar_idx = i / 4;
- vector<Point> barcode_contour(corners.begin() + i, corners.begin() + i + 4);
- drawBarcodeContour(frame, barcode_contour, g_detectOnly || decode_type[bar_idx] != barcode::NONE);
- cout << "BAR[" << bar_idx << "] @ " << Mat(barcode_contour).reshape(2, 1) << ": ";
- if (decode_info.size() > bar_idx)
- {
- if (!decode_info[bar_idx].empty())
- {
- cout << "TYPE: " << decode_type[bar_idx] << " INFO: " << decode_info[bar_idx] << endl;
- }
- else
- {
- cout << "can't decode 1D barcode" << endl;
- }
- }
- else
- {
- cout << "decode information is not available (disabled)" << endl;
- }
- }
- }
- else
- {
- cout << "Barcode is not detected" << endl;
- }
- drawFPS(frame, fps);
- }
- //! [visualize]
- static void
- runBarcode(const Mat &input, vector<Point> &corners, vector<cv::String> &decode_info,
- vector<cv::barcode::BarcodeType> &decode_type
- )
- {
- if (!g_detectOnly)
- {
- //! [detectAndDecode]
- bool result_detection = bardet->detectAndDecode(input, decode_info, decode_type, corners);
- //! [detectAndDecode]
- CV_UNUSED(result_detection);
- }
- else
- {
- //! [detect]
- bool result_detection = bardet->detect(input, corners);
- //! [detect]
- CV_UNUSED(result_detection);
- }
- }
- int liveBarCodeDetect()
- {
- VideoCapture cap(0);
- if (!cap.isOpened())
- {
- cout << "Cannot open a camera" << endl;
- return 2;
- }
- cout << "Press 'd' to switch between decoder and detector" << endl;
- cout << "Press 'ESC' to exit" << endl;
- for (;;)
- {
- Mat frame;
- cap >> frame;
- if (frame.empty())
- {
- cout << "End of video stream" << endl;
- break;
- }
- Mat result;
- if (frame.channels() == 1)
- {
- cvtColor(frame, result, COLOR_GRAY2BGR);
- }
- else
- {
- frame.copyTo(result);
- }
- TickMeter timer;
- //! [output]
- vector<cv::String> decode_info;
- vector<barcode::BarcodeType> decoded_type;
- vector<Point> corners;
- //! [output]
- timer.start();
- runBarcode(frame, corners, decode_info, decoded_type);
- timer.stop();
- double fps = 1 / timer.getTimeSec();
- drawBarcodeResults(result, corners, decode_info, decoded_type, fps);
- if (!result.empty())
- {
- imshow("barcode", result);
- }
- int code = waitKey(1);
- if (code < 0)
- {
- continue;
- } // timeout
- char c = (char) code;
- if (c == 'd')
- {
- g_detectOnly = !g_detectOnly;
- cout << "Switching barcode decoder mode ==> " << (g_detectOnly ? "detect" : "decode") << endl;
- }
- if (c == 27)
- {
- cout << "'ESC' is pressed. Exiting..." << endl;
- break;
- }
- }
- cout << "Exit." << endl;
- return 0;
- }
- int imageBarCodeDetect(const string &in_file)
- {
- const int count_experiments = 10;
- Mat input = imread(in_file, IMREAD_COLOR);
- cout << "Run BarCode" << (g_detectOnly ? " detector" : " decoder") << " on image: " << input.size() << " ("
- << typeToString(input.type()) << ")" << endl;
- vector<Point> corners;
- vector<cv::String> decode_info;
- vector<barcode::BarcodeType> decoded_type;
- TickMeter timer;
- for (size_t i = 0; i < count_experiments; i++)
- {
- corners.clear();
- decode_info.clear();
- timer.start();
- runBarcode(input, corners, decode_info, decoded_type);
- timer.stop();
- }
- double fps = count_experiments / timer.getTimeSec();
- cout << "FPS: " << fps << endl;
- Mat result;
- input.copyTo(result);
- drawBarcodeResults(result, corners, decode_info, decoded_type, fps);
- if (!g_out_file_name.empty())
- {
- string out_file = g_out_file_name + g_out_file_ext;
- cout << "Saving result: " << out_file << endl;
- imwrite(out_file, result);
- }
- imshow("barcode", result);
- waitKey(1);
- cout << "Press any key to exit ..." << endl;
- waitKey(0);
- cout << "Exit." << endl;
- return 0;
- }
|