// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. #include "test_precomp.hpp" #include "opencv2/objdetect/barcode.hpp" #include using namespace std; namespace opencv_test{namespace{ typedef std::set StringSet; // Convert ';'-separated strings to a set inline static StringSet toSet(const string &line) { StringSet res; string::size_type it = 0, ti; while (true) { ti = line.find(';', it); if (ti == string::npos) { res.insert(string(line, it, line.size() - it)); break; } res.insert(string(line, it, ti - it)); it = ti + 1; } return res; } // Convert vector of strings to a set inline static StringSet toSet(const vector &lines) { StringSet res; for (const string & line : lines) res.insert(line); return res; } // Get all keys of a map in a vector template inline static vector getKeys(const map &m) { vector res; for (const auto & it : m) res.push_back(it.first); return res; } struct BarcodeResult { string type; string data; }; map testResults { { "single/book.jpg", {"EAN_13", "9787115279460"} }, { "single/bottle_1.jpg", {"EAN_13", "6922255451427"} }, { "single/bottle_2.jpg", {"EAN_13", "6921168509256"} }, { "multiple/4_barcodes.jpg", {"EAN_13;EAN_13;EAN_13;EAN_13", "9787564350840;9783319200064;9787118081473;9787122276124"} }, }; typedef testing::TestWithParam< string > BarcodeDetector_main; TEST_P(BarcodeDetector_main, interface) { const string fname = GetParam(); const string image_path = findDataFile(string("barcode/") + fname); const StringSet expected_lines = toSet(testResults[fname].data); const StringSet expected_types = toSet(testResults[fname].type); const size_t expected_count = expected_lines.size(); // assume codes are unique // TODO: verify points location Mat img = imread(image_path); ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path; barcode::BarcodeDetector det; vector points; vector types; vector lines; // common interface (single) { bool res = det.detect(img, points); ASSERT_TRUE(res); EXPECT_EQ(expected_count * 4, points.size()); } { string res = det.decode(img, points); ASSERT_FALSE(res.empty()); EXPECT_EQ(1u, expected_lines.count(res)); } { string res = det.detectAndDecode(img, points); ASSERT_FALSE(res.empty()); EXPECT_EQ(1u, expected_lines.count(res)); EXPECT_EQ(4u, points.size()); } // common interface (multi) { bool res = det.detectMulti(img, points); ASSERT_TRUE(res); EXPECT_EQ(expected_count * 4, points.size()); } { bool res = det.decodeMulti(img, points, lines); ASSERT_TRUE(res); EXPECT_EQ(expected_lines, toSet(lines)); } // specific interface { bool res = det.decodeWithType(img, points, lines, types); ASSERT_TRUE(res); EXPECT_EQ(expected_types, toSet(types)); EXPECT_EQ(expected_lines, toSet(lines)); } { bool res = det.detectAndDecodeWithType(img, lines, types, points); ASSERT_TRUE(res); EXPECT_EQ(expected_types, toSet(types)); EXPECT_EQ(expected_lines, toSet(lines)); } } INSTANTIATE_TEST_CASE_P(/**/, BarcodeDetector_main, testing::ValuesIn(getKeys(testResults))); TEST(BarcodeDetector_base, invalid) { auto bardet = barcode::BarcodeDetector(); std::vector corners; vector decoded_info; Mat zero_image = Mat::zeros(256, 256, CV_8UC1); EXPECT_FALSE(bardet.detectMulti(zero_image, corners)); corners = std::vector(4); EXPECT_ANY_THROW(bardet.decodeMulti(zero_image, corners, decoded_info)); } struct ParamStruct { double down_thresh; vector scales; double grad_thresh; unsigned res_count; }; inline static std::ostream &operator<<(std::ostream &out, const ParamStruct &p) { out << "(" << p.down_thresh << ", "; for(float val : p.scales) out << val << ", "; out << p.grad_thresh << ")"; return out; } ParamStruct param_list[] = { { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 4 }, // default values -> 4 codes { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 1024, 2 }, { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 2048, 0 }, { 128, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 3 }, { 64, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 2 }, { 128, {0.0000001f}, 64, 1 }, { 128, {0.0000001f, 0.0001f}, 64, 1 }, { 128, {0.0000001f, 0.1f}, 64, 1 }, { 512, {0.1f}, 64, 0 }, }; typedef testing::TestWithParam BarcodeDetector_parameters_tune; TEST_P(BarcodeDetector_parameters_tune, accuracy) { const ParamStruct param = GetParam(); const string fname = "multiple/4_barcodes.jpg"; const string image_path = findDataFile(string("barcode/") + fname); const Mat img = imread(image_path); ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path; auto bardet = barcode::BarcodeDetector(); bardet.setDownsamplingThreshold(param.down_thresh); bardet.setDetectorScales(param.scales); bardet.setGradientThreshold(param.grad_thresh); vector points; bardet.detectMulti(img, points); EXPECT_EQ(points.size() / 4, param.res_count); } INSTANTIATE_TEST_CASE_P(/**/, BarcodeDetector_parameters_tune, testing::ValuesIn(param_list)); TEST(BarcodeDetector_parameters, regression) { const double expected_dt = 1024, expected_gt = 256; const vector expected_ds = {0.1f}; vector ds_value = {0.0f}; auto bardet = barcode::BarcodeDetector(); bardet.setDownsamplingThreshold(expected_dt).setDetectorScales(expected_ds).setGradientThreshold(expected_gt); double dt_value = bardet.getDownsamplingThreshold(); bardet.getDetectorScales(ds_value); double gt_value = bardet.getGradientThreshold(); EXPECT_EQ(expected_dt, dt_value); EXPECT_EQ(expected_ds, ds_value); EXPECT_EQ(expected_gt, gt_value); } TEST(BarcodeDetector_parameters, invalid) { auto bardet = barcode::BarcodeDetector(); EXPECT_ANY_THROW(bardet.setDownsamplingThreshold(-1)); EXPECT_ANY_THROW(bardet.setDetectorScales(vector {})); EXPECT_ANY_THROW(bardet.setDetectorScales(vector {-1})); EXPECT_ANY_THROW(bardet.setDetectorScales(vector {1.5})); EXPECT_ANY_THROW(bardet.setDetectorScales(vector (17, 0.5))); EXPECT_ANY_THROW(bardet.setGradientThreshold(-0.1)); } }} // opencv_test::::