mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
6.7 KiB
230 lines
6.7 KiB
// 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 <set> |
|
|
|
using namespace std; |
|
|
|
namespace opencv_test{namespace{ |
|
|
|
typedef std::set<string> 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<string> &lines) |
|
{ |
|
StringSet res; |
|
for (const string & line : lines) |
|
res.insert(line); |
|
return res; |
|
} |
|
|
|
// Get all keys of a map in a vector |
|
template<typename T, typename V> |
|
inline static vector<T> getKeys(const map<T, V> &m) |
|
{ |
|
vector<T> res; |
|
for (const auto & it : m) |
|
res.push_back(it.first); |
|
return res; |
|
} |
|
|
|
struct BarcodeResult |
|
{ |
|
string type; |
|
string data; |
|
}; |
|
|
|
map<string, BarcodeResult> 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<Point2f> points; |
|
vector<string> types; |
|
vector<string> 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<Point> corners; |
|
vector<cv::String> decoded_info; |
|
Mat zero_image = Mat::zeros(256, 256, CV_8UC1); |
|
EXPECT_FALSE(bardet.detectMulti(zero_image, corners)); |
|
corners = std::vector<Point>(4); |
|
EXPECT_ANY_THROW(bardet.decodeMulti(zero_image, corners, decoded_info)); |
|
} |
|
|
|
struct ParamStruct |
|
{ |
|
double down_thresh; |
|
vector<float> 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<ParamStruct> 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<Point2f> 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<float> expected_ds = {0.1f}; |
|
vector<float> 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<float> {})); |
|
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {-1})); |
|
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {1.5})); |
|
EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> (17, 0.5))); |
|
EXPECT_ANY_THROW(bardet.setGradientThreshold(-0.1)); |
|
} |
|
|
|
}} // opencv_test::<anonymous>::
|
|
|