diff --git a/doc/tutorials/objdetect/barcode_detect_and_decode/barcode_detect_and_decode.markdown b/doc/tutorials/objdetect/barcode_detect_and_decode/barcode_detect_and_decode.markdown index 7b7d8b4a0e..f2daf466f6 100644 --- a/doc/tutorials/objdetect/barcode_detect_and_decode/barcode_detect_and_decode.markdown +++ b/doc/tutorials/objdetect/barcode_detect_and_decode/barcode_detect_and_decode.markdown @@ -33,7 +33,7 @@ While coding, we firstly need to create a cv::barcode::BarcodeDetector object. I #### Initialization -Optionally user can construct barcode detector with super resolution model which should be downloaded from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode (`sr.caffemodel`, `sr.prototxt`). +Optionally user can construct barcode detector with a super resolution model, passed as a single-file ONNX network (`sr.onnx`). A converted model can be downloaded from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode. Caffe models (`sr.prototxt` / `sr.caffemodel`) are no longer supported. @snippet cpp/barcode.cpp initialize diff --git a/modules/objdetect/include/opencv2/objdetect/barcode.hpp b/modules/objdetect/include/opencv2/objdetect/barcode.hpp index c20b67c0b2..e1dd3f4b0f 100644 --- a/modules/objdetect/include/opencv2/objdetect/barcode.hpp +++ b/modules/objdetect/include/opencv2/objdetect/barcode.hpp @@ -18,16 +18,22 @@ namespace barcode { class CV_EXPORTS_W_SIMPLE BarcodeDetector : public cv::GraphicalCodeDetector { public: - /** @brief Initialize the BarcodeDetector. + /** @brief Initialize the BarcodeDetector. Super resolution is disabled. */ CV_WRAP BarcodeDetector(); - /** @brief Initialize the BarcodeDetector. + + /** @brief Initialize the BarcodeDetector with a Super Resolution model. * - * Parameters allow to load _optional_ Super Resolution DNN model for better quality. - * @param prototxt_path prototxt file path for the super resolution model - * @param model_path model file path for the super resolution model + * Loads a Super Resolution DNN model in ONNX format, used to upscale small/low-quality + * barcode crops before decoding for better quality. + * + * @note Caffe models (`sr.prototxt` / `sr.caffemodel`) are no longer supported; convert + * the model to ONNX (a converted `sr.onnx` is available from + * https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode). + * + * @param super_resolution_model_path path to a single-file ONNX Super Resolution model. */ - CV_WRAP BarcodeDetector(CV_WRAP_FILE_PATH const std::string &prototxt_path, CV_WRAP_FILE_PATH const std::string &model_path); + CV_WRAP BarcodeDetector(CV_WRAP_FILE_PATH const std::string &super_resolution_model_path); ~BarcodeDetector(); /** @brief Decodes barcode in image once it's found by the detect() method. diff --git a/modules/objdetect/src/barcode.cpp b/modules/objdetect/src/barcode.cpp index 5b38e03956..d3f35734cd 100644 --- a/modules/objdetect/src/barcode.cpp +++ b/modules/objdetect/src/barcode.cpp @@ -339,22 +339,21 @@ bool BarcodeImpl::detectAndDecodeMulti(InputArray img, vector &decoded_i // Public class implementation BarcodeDetector::BarcodeDetector() - : BarcodeDetector(string(), string()) + : BarcodeDetector(std::string()) { } -BarcodeDetector::BarcodeDetector(const string &prototxt_path, const string &model_path) +BarcodeDetector::BarcodeDetector(const string &super_resolution_model_path) { Ptr p_ = new BarcodeImpl(); p = p_; p_->sr = make_shared(); - // The Super Resolution model is now a single-file ONNX network; the legacy Caffe - // prototxt argument is retained for API compatibility but is no longer used. - CV_UNUSED(prototxt_path); - if (!model_path.empty()) + // The optional Super Resolution model is a single-file ONNX network (Caffe support + // has been removed). An empty path simply disables super resolution. + if (!super_resolution_model_path.empty()) { - CV_Assert(utils::fs::exists(model_path)); - int res = p_->sr->init(model_path); + CV_Assert(utils::fs::exists(super_resolution_model_path)); + int res = p_->sr->init(super_resolution_model_path); CV_Assert(res == 0); p_->use_nn_sr = true; } diff --git a/modules/objdetect/test/test_barcode.cpp b/modules/objdetect/test/test_barcode.cpp index 94542ca39b..3784e888f7 100644 --- a/modules/objdetect/test/test_barcode.cpp +++ b/modules/objdetect/test/test_barcode.cpp @@ -227,4 +227,27 @@ TEST(BarcodeDetector_parameters, invalid) EXPECT_ANY_THROW(bardet.setGradientThreshold(-0.1)); } +TEST(BarcodeDetector_super_resolution, accuracy) +{ + // Reuse the existing WeChat Super Resolution ONNX model shipped in opencv_extra. + const string sr_path = findDataFile("dnn/wechat_2021-01/sr.onnx", false); + if (sr_path.empty()) + throw SkipTestException("Missing super resolution model (dnn/wechat_2021-01/sr.onnx)"); + + const string fname = "single/book.jpg"; + const string image_path = findDataFile("barcode/" + fname); + Mat img = imread(image_path); + ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path; + + // Construct with the ONNX super resolution model enabled. + barcode::BarcodeDetector det(sr_path); + + vector lines, types; + vector points; + bool res = det.detectAndDecodeWithType(img, lines, types, points); + ASSERT_TRUE(res); + EXPECT_EQ(toSet(testResults[fname].type), toSet(types)); + EXPECT_EQ(toSet(testResults[fname].data), toSet(lines)); +} + }} // opencv_test:::: diff --git a/samples/cpp/barcode.cpp b/samples/cpp/barcode.cpp index 5955d4a74d..e820788e47 100644 --- a/samples/cpp/barcode.cpp +++ b/samples/cpp/barcode.cpp @@ -175,8 +175,7 @@ int main(int argc, char **argv) "{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 }"; + "{sr_model | | optional super resolution ONNX model path (e.g. sr.onnx) }"; 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")) @@ -186,7 +185,6 @@ int main(int argc, char **argv) } const string in_file = cmd_parser.get("in"); const string out_file = cmd_parser.get("out"); - const string sr_prototxt = cmd_parser.get("sr_prototxt"); const string sr_model = cmd_parser.get("sr_model"); if (!cmd_parser.check()) { @@ -199,17 +197,17 @@ int main(int argc, char **argv) //! [initialize] try { - app.bardet = makePtr(sr_prototxt, sr_model); + app.bardet = makePtr(sr_model); } catch (const std::exception& e) { cout << "\n---------------------------------------------------------------\n" "Failed to initialize super resolution.\n" - "Please, download 'sr.*' from\n" + "Please, download 'sr.onnx' 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" + "and put it into the current directory.\n" + "Or you can leave sr_model unspecified.\n" "---------------------------------------------------------------\n"; cout << e.what() << endl; return -1;