test_barcode.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #include "test_precomp.hpp"
  5. #include "opencv2/objdetect/barcode.hpp"
  6. #include <set>
  7. using namespace std;
  8. namespace opencv_test{namespace{
  9. typedef std::set<string> StringSet;
  10. // Convert ';'-separated strings to a set
  11. inline static StringSet toSet(const string &line)
  12. {
  13. StringSet res;
  14. string::size_type it = 0, ti;
  15. while (true)
  16. {
  17. ti = line.find(';', it);
  18. if (ti == string::npos)
  19. {
  20. res.insert(string(line, it, line.size() - it));
  21. break;
  22. }
  23. res.insert(string(line, it, ti - it));
  24. it = ti + 1;
  25. }
  26. return res;
  27. }
  28. // Convert vector of strings to a set
  29. inline static StringSet toSet(const vector<string> &lines)
  30. {
  31. StringSet res;
  32. for (const string & line : lines)
  33. res.insert(line);
  34. return res;
  35. }
  36. // Get all keys of a map in a vector
  37. template<typename T, typename V>
  38. inline static vector<T> getKeys(const map<T, V> &m)
  39. {
  40. vector<T> res;
  41. for (const auto & it : m)
  42. res.push_back(it.first);
  43. return res;
  44. }
  45. struct BarcodeResult
  46. {
  47. string type;
  48. string data;
  49. };
  50. map<string, BarcodeResult> testResults {
  51. { "single/book.jpg", {"EAN_13", "9787115279460"} },
  52. { "single/bottle_1.jpg", {"EAN_13", "6922255451427"} },
  53. { "single/bottle_2.jpg", {"EAN_13", "6921168509256"} },
  54. { "multiple/4_barcodes.jpg", {"EAN_13;EAN_13;EAN_13;EAN_13", "9787564350840;9783319200064;9787118081473;9787122276124"} },
  55. };
  56. typedef testing::TestWithParam< string > BarcodeDetector_main;
  57. TEST_P(BarcodeDetector_main, interface)
  58. {
  59. const string fname = GetParam();
  60. const string image_path = findDataFile(string("barcode/") + fname);
  61. const StringSet expected_lines = toSet(testResults[fname].data);
  62. const StringSet expected_types = toSet(testResults[fname].type);
  63. const size_t expected_count = expected_lines.size(); // assume codes are unique
  64. // TODO: verify points location
  65. Mat img = imread(image_path);
  66. ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path;
  67. barcode::BarcodeDetector det;
  68. vector<Point2f> points;
  69. vector<string> types;
  70. vector<string> lines;
  71. // common interface (single)
  72. {
  73. bool res = det.detect(img, points);
  74. ASSERT_TRUE(res);
  75. EXPECT_EQ(expected_count * 4, points.size());
  76. }
  77. {
  78. string res = det.decode(img, points);
  79. ASSERT_FALSE(res.empty());
  80. EXPECT_EQ(1u, expected_lines.count(res));
  81. }
  82. {
  83. string res = det.detectAndDecode(img, points);
  84. ASSERT_FALSE(res.empty());
  85. EXPECT_EQ(1u, expected_lines.count(res));
  86. EXPECT_EQ(4u, points.size());
  87. }
  88. // common interface (multi)
  89. {
  90. bool res = det.detectMulti(img, points);
  91. ASSERT_TRUE(res);
  92. EXPECT_EQ(expected_count * 4, points.size());
  93. }
  94. {
  95. bool res = det.decodeMulti(img, points, lines);
  96. ASSERT_TRUE(res);
  97. EXPECT_EQ(expected_lines, toSet(lines));
  98. }
  99. // specific interface
  100. {
  101. bool res = det.decodeWithType(img, points, lines, types);
  102. ASSERT_TRUE(res);
  103. EXPECT_EQ(expected_types, toSet(types));
  104. EXPECT_EQ(expected_lines, toSet(lines));
  105. }
  106. {
  107. bool res = det.detectAndDecodeWithType(img, lines, types, points);
  108. ASSERT_TRUE(res);
  109. EXPECT_EQ(expected_types, toSet(types));
  110. EXPECT_EQ(expected_lines, toSet(lines));
  111. }
  112. }
  113. INSTANTIATE_TEST_CASE_P(/**/, BarcodeDetector_main, testing::ValuesIn(getKeys(testResults)));
  114. TEST(BarcodeDetector_base, invalid)
  115. {
  116. auto bardet = barcode::BarcodeDetector();
  117. std::vector<Point> corners;
  118. vector<cv::String> decoded_info;
  119. Mat zero_image = Mat::zeros(256, 256, CV_8UC1);
  120. EXPECT_FALSE(bardet.detectMulti(zero_image, corners));
  121. corners = std::vector<Point>(4);
  122. EXPECT_ANY_THROW(bardet.decodeMulti(zero_image, corners, decoded_info));
  123. }
  124. struct ParamStruct
  125. {
  126. double down_thresh;
  127. vector<float> scales;
  128. double grad_thresh;
  129. unsigned res_count;
  130. };
  131. inline static std::ostream &operator<<(std::ostream &out, const ParamStruct &p)
  132. {
  133. out << "(" << p.down_thresh << ", ";
  134. for(float val : p.scales)
  135. out << val << ", ";
  136. out << p.grad_thresh << ")";
  137. return out;
  138. }
  139. ParamStruct param_list[] = {
  140. { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 4 }, // default values -> 4 codes
  141. { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 1024, 2 },
  142. { 512, {0.01f, 0.03f, 0.06f, 0.08f}, 2048, 0 },
  143. { 128, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 3 },
  144. { 64, {0.01f, 0.03f, 0.06f, 0.08f}, 64, 2 },
  145. { 128, {0.0000001f}, 64, 1 },
  146. { 128, {0.0000001f, 0.0001f}, 64, 1 },
  147. { 128, {0.0000001f, 0.1f}, 64, 1 },
  148. { 512, {0.1f}, 64, 0 },
  149. };
  150. typedef testing::TestWithParam<ParamStruct> BarcodeDetector_parameters_tune;
  151. TEST_P(BarcodeDetector_parameters_tune, accuracy)
  152. {
  153. const ParamStruct param = GetParam();
  154. const string fname = "multiple/4_barcodes.jpg";
  155. const string image_path = findDataFile(string("barcode/") + fname);
  156. const Mat img = imread(image_path);
  157. ASSERT_FALSE(img.empty()) << "Can't read image: " << image_path;
  158. auto bardet = barcode::BarcodeDetector();
  159. bardet.setDownsamplingThreshold(param.down_thresh);
  160. bardet.setDetectorScales(param.scales);
  161. bardet.setGradientThreshold(param.grad_thresh);
  162. vector<Point2f> points;
  163. bardet.detectMulti(img, points);
  164. EXPECT_EQ(points.size() / 4, param.res_count);
  165. }
  166. INSTANTIATE_TEST_CASE_P(/**/, BarcodeDetector_parameters_tune, testing::ValuesIn(param_list));
  167. TEST(BarcodeDetector_parameters, regression)
  168. {
  169. const double expected_dt = 1024, expected_gt = 256;
  170. const vector<float> expected_ds = {0.1f};
  171. vector<float> ds_value = {0.0f};
  172. auto bardet = barcode::BarcodeDetector();
  173. bardet.setDownsamplingThreshold(expected_dt).setDetectorScales(expected_ds).setGradientThreshold(expected_gt);
  174. double dt_value = bardet.getDownsamplingThreshold();
  175. bardet.getDetectorScales(ds_value);
  176. double gt_value = bardet.getGradientThreshold();
  177. EXPECT_EQ(expected_dt, dt_value);
  178. EXPECT_EQ(expected_ds, ds_value);
  179. EXPECT_EQ(expected_gt, gt_value);
  180. }
  181. TEST(BarcodeDetector_parameters, invalid)
  182. {
  183. auto bardet = barcode::BarcodeDetector();
  184. EXPECT_ANY_THROW(bardet.setDownsamplingThreshold(-1));
  185. EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {}));
  186. EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {-1}));
  187. EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> {1.5}));
  188. EXPECT_ANY_THROW(bardet.setDetectorScales(vector<float> (17, 0.5)));
  189. EXPECT_ANY_THROW(bardet.setGradientThreshold(-0.1));
  190. }
  191. }} // opencv_test::<anonymous>::