test_qrcode_encode.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  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. namespace opencv_test { namespace {
  6. std::string encode_qrcode_images_name[] = {
  7. "version1_mode1.png", "version1_mode2.png", "version1_mode4.png",
  8. "version2_mode1.png", "version2_mode2.png", "version2_mode4.png",
  9. "version3_mode2.png", "version3_mode4.png",
  10. "version4_mode4.png"
  11. };
  12. std::string encode_qrcode_eci_images_name[] = {
  13. "version1_mode7.png",
  14. "version2_mode7.png",
  15. "version3_mode7.png",
  16. "version4_mode7.png",
  17. "version5_mode7.png"
  18. };
  19. const Size fixed_size = Size(200, 200);
  20. const float border_width = 2.0;
  21. int establishCapacity(QRCodeEncoder::EncodeMode mode, int version, int capacity)
  22. {
  23. int result = 0;
  24. capacity *= 8;
  25. capacity -= 4;
  26. switch (mode)
  27. {
  28. case QRCodeEncoder::MODE_NUMERIC:
  29. {
  30. if (version >= 10)
  31. capacity -= 12;
  32. else
  33. capacity -= 10;
  34. int tmp = capacity / 10;
  35. result = tmp * 3;
  36. if (tmp * 10 + 7 <= capacity)
  37. result += 2;
  38. else if (tmp * 10 + 4 <= capacity)
  39. result += 1;
  40. break;
  41. }
  42. case QRCodeEncoder::MODE_ALPHANUMERIC:
  43. {
  44. if (version < 10)
  45. capacity -= 9;
  46. else
  47. capacity -= 13;
  48. int tmp = capacity / 11;
  49. result = tmp * 2;
  50. if (tmp * 11 + 6 <= capacity)
  51. result++;
  52. break;
  53. }
  54. case QRCodeEncoder::MODE_BYTE:
  55. {
  56. if (version > 9)
  57. capacity -= 16;
  58. else
  59. capacity -= 8;
  60. result = capacity / 8;
  61. break;
  62. }
  63. default:
  64. break;
  65. }
  66. return result;
  67. }
  68. // #define UPDATE_TEST_DATA
  69. #ifdef UPDATE_TEST_DATA
  70. TEST(Objdetect_QRCode_Encode, generate_test_data)
  71. {
  72. const std::string root = "qrcode/encode";
  73. const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
  74. FileStorage file_config(dataset_config, FileStorage::WRITE);
  75. file_config << "test_images" << "[";
  76. size_t images_count = sizeof(encode_qrcode_images_name) / sizeof(encode_qrcode_images_name[0]);
  77. for (size_t i = 0; i < images_count; i++)
  78. {
  79. file_config << "{:" << "image_name" << encode_qrcode_images_name[i];
  80. std::string image_path = findDataFile(root + "/" + encode_qrcode_images_name[i]);
  81. Mat src = imread(image_path, IMREAD_GRAYSCALE);
  82. Mat straight_barcode;
  83. EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
  84. std::vector<Point2f> corners(4);
  85. corners[0] = Point2f(border_width, border_width);
  86. corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
  87. corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
  88. corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
  89. Mat resized_src;
  90. resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
  91. float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
  92. float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
  93. for(size_t j = 0; j < corners.size(); j++)
  94. {
  95. corners[j].x = corners[j].x * width_ratio;
  96. corners[j].y = corners[j].y * height_ratio;
  97. }
  98. std::string decoded_info = "";
  99. EXPECT_TRUE(decodeQRCode(resized_src, corners, decoded_info, straight_barcode)) << "The QR code cannot be decoded: " << image_path;
  100. file_config << "info" << decoded_info;
  101. file_config << "}";
  102. }
  103. file_config << "]";
  104. file_config.release();
  105. }
  106. #else
  107. typedef testing::TestWithParam< std::string > Objdetect_QRCode_Encode;
  108. TEST_P(Objdetect_QRCode_Encode, regression) {
  109. const int pixels_error = 3;
  110. const std::string name_current_image = GetParam();
  111. const std::string root = "qrcode/encode";
  112. std::string image_path = findDataFile(root + "/" + name_current_image);
  113. const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
  114. FileStorage file_config(dataset_config, FileStorage::READ);
  115. ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
  116. {
  117. FileNode images_list = file_config["test_images"];
  118. size_t images_count = static_cast<size_t>(images_list.size());
  119. ASSERT_GT(images_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
  120. for (size_t index = 0; index < images_count; index++)
  121. {
  122. FileNode config = images_list[(int)index];
  123. std::string name_test_image = config["image_name"];
  124. if (name_test_image == name_current_image)
  125. {
  126. std::string original_info = config["info"];
  127. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create();
  128. Mat result;
  129. encoder->encode(original_info, result);
  130. EXPECT_FALSE(result.empty()) << "Can't generate QR code image";
  131. Mat src = imread(image_path, IMREAD_GRAYSCALE);
  132. Mat straight_barcode;
  133. EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
  134. double diff_norm = cvtest::norm(result - src, NORM_L1);
  135. EXPECT_NEAR(diff_norm, 0.0, pixels_error) << "The generated QRcode is not same as test data. The difference: " << diff_norm;
  136. return; // done
  137. }
  138. }
  139. FAIL() << "Not found results in config file:" << dataset_config
  140. << "\nRe-run tests with enabled UPDATE_ENCODE_TEST_DATA macro to update test data.";
  141. }
  142. }
  143. typedef testing::TestWithParam< std::string > Objdetect_QRCode_Encode_ECI;
  144. TEST_P(Objdetect_QRCode_Encode_ECI, regression) {
  145. const int pixels_error = 3;
  146. const std::string name_current_image = GetParam();
  147. const std::string root = "qrcode/encode";
  148. std::string image_path = findDataFile(root + "/" + name_current_image);
  149. const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
  150. FileStorage file_config(dataset_config, FileStorage::READ);
  151. ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
  152. {
  153. FileNode images_list = file_config["test_images"];
  154. size_t images_count = static_cast<size_t>(images_list.size());
  155. ASSERT_GT(images_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
  156. QRCodeEncoder::Params params;
  157. params.mode = QRCodeEncoder::MODE_ECI;
  158. for (size_t index = 0; index < images_count; index++)
  159. {
  160. FileNode config = images_list[(int)index];
  161. std::string name_test_image = config["image_name"];
  162. if (name_test_image == name_current_image)
  163. {
  164. std::string original_info = config["info"];
  165. Mat result;
  166. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
  167. encoder->encode(original_info, result);
  168. EXPECT_FALSE(result.empty()) << "Can't generate QR code image";
  169. Mat src = imread(image_path, IMREAD_GRAYSCALE);
  170. Mat straight_barcode;
  171. EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
  172. double diff_norm = cvtest::norm(result - src, NORM_L1);
  173. EXPECT_NEAR(diff_norm, 0.0, pixels_error) << "The generated QRcode is not same as test data. The difference: " << diff_norm;
  174. return; // done
  175. }
  176. }
  177. FAIL() << "Not found results in config file:" << dataset_config
  178. << "\nRe-run tests with enabled UPDATE_ENCODE_TEST_DATA macro to update test data.";
  179. }
  180. }
  181. INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Encode, testing::ValuesIn(encode_qrcode_images_name));
  182. INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Encode_ECI, testing::ValuesIn(encode_qrcode_eci_images_name));
  183. TEST(Objdetect_QRCode_Encode_Decode, regression)
  184. {
  185. const std::string root = "qrcode/decode_encode";
  186. const int min_version = 1;
  187. const int test_max_version = 5;
  188. const int max_ec_level = 3;
  189. const std::string dataset_config = findDataFile(root + "/" + "symbol_sets.json");
  190. const std::string version_config = findDataFile(root + "/" + "capacity.json");
  191. FileStorage file_config(dataset_config, FileStorage::READ);
  192. FileStorage capacity_config(version_config, FileStorage::READ);
  193. ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
  194. ASSERT_TRUE(capacity_config.isOpened()) << "Can't read validation data: " << version_config;
  195. FileNode mode_list = file_config["symbols_sets"];
  196. FileNode capacity_list = capacity_config["version_ecc_capacity"];
  197. size_t mode_count = static_cast<size_t>(mode_list.size());
  198. ASSERT_GT(mode_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
  199. const int testing_modes = 3;
  200. QRCodeEncoder::EncodeMode modes[testing_modes] = {
  201. QRCodeEncoder::MODE_NUMERIC,
  202. QRCodeEncoder::MODE_ALPHANUMERIC,
  203. QRCodeEncoder::MODE_BYTE
  204. };
  205. for (int i = 0; i < testing_modes; i++)
  206. {
  207. QRCodeEncoder::EncodeMode mode = modes[i];
  208. FileNode config = mode_list[i];
  209. std::string symbol_set = config["symbols_set"];
  210. for(int version = min_version; version <= test_max_version; version++)
  211. {
  212. FileNode capa_config = capacity_list[version - 1];
  213. for(int level = 0; level <= max_ec_level; level++)
  214. {
  215. const int cur_capacity = capa_config["ecc_level"][level];
  216. int true_capacity = establishCapacity(mode, version, cur_capacity);
  217. std::string input_info = symbol_set;
  218. std::mt19937 rand_gen {1};
  219. std::shuffle(input_info.begin(), input_info.end(), rand_gen);
  220. int count = 0;
  221. if((int)input_info.length() > true_capacity)
  222. {
  223. input_info = input_info.substr(0, true_capacity);
  224. }
  225. else
  226. {
  227. while ((int)input_info.length() != true_capacity)
  228. {
  229. input_info += input_info.substr(count%(int)input_info.length(), 1);
  230. count++;
  231. }
  232. }
  233. QRCodeEncoder::Params params;
  234. params.version = version;
  235. params.correction_level = static_cast<QRCodeEncoder::CorrectionLevel>(level);
  236. params.mode = mode;
  237. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
  238. Mat qrcode;
  239. encoder->encode(input_info, qrcode);
  240. EXPECT_TRUE(!qrcode.empty()) << "Can't generate this QR image (" << "mode: " << (int)mode <<
  241. " version: "<< version <<" error correction level: "<< (int)level <<")";
  242. std::vector<Point2f> corners(4);
  243. corners[0] = Point2f(border_width, border_width);
  244. corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
  245. corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
  246. corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
  247. Mat resized_src;
  248. resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
  249. float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
  250. float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
  251. for(size_t k = 0; k < corners.size(); k++)
  252. {
  253. corners[k].x = corners[k].x * width_ratio;
  254. corners[k].y = corners[k].y * height_ratio;
  255. }
  256. Mat straight_barcode;
  257. std::string output_info = QRCodeDetector().decode(resized_src, corners, straight_barcode);
  258. EXPECT_FALSE(output_info.empty())
  259. << "The generated QRcode cannot be decoded." << " Mode: " << (int)mode
  260. << " version: " << version << " error correction level: " << (int)level;
  261. EXPECT_EQ(input_info, output_info) << "The generated QRcode is not same as test data." << " Mode: " << (int)mode <<
  262. " version: " << version << " error correction level: " << (int)level;
  263. }
  264. }
  265. }
  266. }
  267. TEST(Objdetect_QRCode_Encode_Kanji, regression)
  268. {
  269. QRCodeEncoder::Params params;
  270. params.mode = QRCodeEncoder::MODE_KANJI;
  271. Mat qrcode;
  272. const int testing_versions = 3;
  273. std::string input_infos[testing_versions] = {"\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x90\xa2\x8a\x45", // "Hello World" in Japanese
  274. "\x82\xa8\x95\xa0\x82\xaa\x8b\xf3\x82\xa2\x82\xc4\x82\xa2\x82\xdc\x82\xb7", // "I am hungry" in Japanese
  275. "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x81\x41\x8e\x84\x82\xcd\x8f\xad\x82\xb5\x93\xfa\x96\x7b\x8c\xea\x82\xf0\x98\x62\x82\xb5\x82\xdc\x82\xb7" // "Hello, I speak a little Japanese" in Japanese
  276. };
  277. for (int i = 0; i < testing_versions; i++)
  278. {
  279. std::string input_info = input_infos[i];
  280. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
  281. encoder->encode(input_info, qrcode);
  282. std::vector<Point2f> corners(4);
  283. corners[0] = Point2f(border_width, border_width);
  284. corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
  285. corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
  286. corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
  287. Mat resized_src;
  288. resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
  289. float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
  290. float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
  291. for(size_t j = 0; j < corners.size(); j++)
  292. {
  293. corners[j].x = corners[j].x * width_ratio;
  294. corners[j].y = corners[j].y * height_ratio;
  295. }
  296. Mat straight_barcode;
  297. QRCodeDetector detector;
  298. std::string decoded_info = detector.decode(resized_src, corners, straight_barcode);
  299. EXPECT_FALSE(decoded_info.empty()) << "The generated QRcode cannot be decoded.";
  300. EXPECT_EQ(input_info, decoded_info);
  301. EXPECT_EQ(detector.getEncoding(), QRCodeEncoder::ECIEncodings::ECI_SHIFT_JIS);
  302. }
  303. }
  304. TEST(Objdetect_QRCode_Encode_Decode_Structured_Append, regression)
  305. {
  306. // disabled since QR decoder probably doesn't support structured append mode qr codes
  307. const std::string root = "qrcode/decode_encode";
  308. const std::string dataset_config = findDataFile(root + "/" + "symbol_sets.json");
  309. const std::string version_config = findDataFile(root + "/" + "capacity.json");
  310. FileStorage file_config(dataset_config, FileStorage::READ);
  311. ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
  312. FileNode mode_list = file_config["symbols_sets"];
  313. size_t mode_count = static_cast<size_t>(mode_list.size());
  314. ASSERT_GT(mode_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
  315. int modes[] = {1, 2, 4};
  316. const int min_stuctures_num = 2;
  317. const int max_stuctures_num = 5;
  318. for (int i = 0; i < 3; i++)
  319. {
  320. int mode = modes[i];
  321. FileNode config = mode_list[i];
  322. std::string symbol_set = config["symbols_set"];
  323. std::string input_info = symbol_set;
  324. std::mt19937 rand_gen {1};
  325. std::shuffle(input_info.begin(), input_info.end(), rand_gen);
  326. for (int j = min_stuctures_num; j < max_stuctures_num; j++)
  327. {
  328. QRCodeEncoder::Params params;
  329. params.structure_number = j;
  330. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
  331. vector<Mat> qrcodes;
  332. encoder->encodeStructuredAppend(input_info, qrcodes);
  333. EXPECT_TRUE(!qrcodes.empty()) << "Can't generate this QR images";
  334. CV_CheckEQ(qrcodes.size(), (size_t)j, "Number of QR codes");
  335. std::vector<Point2f> corners(4 * qrcodes.size());
  336. for (size_t k = 0; k < qrcodes.size(); k++)
  337. {
  338. Mat qrcode = qrcodes[k];
  339. corners[4 * k] = Point2f(border_width, border_width);
  340. corners[4 * k + 1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
  341. corners[4 * k + 2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
  342. corners[4 * k + 3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
  343. float width_ratio = fixed_size.width * 1.0f / qrcode.cols;
  344. float height_ratio = fixed_size.height * 1.0f / qrcode.rows;
  345. resize(qrcode, qrcodes[k], fixed_size, 0, 0, INTER_AREA);
  346. for (size_t ki = 0; ki < 4; ki++)
  347. {
  348. corners[4 * k + ki].x = corners[4 * k + ki].x * width_ratio + fixed_size.width * k;
  349. corners[4 * k + ki].y = corners[4 * k + ki].y * height_ratio;
  350. }
  351. }
  352. Mat resized_src;
  353. hconcat(qrcodes, resized_src);
  354. std::vector<cv::String> decoded_info;
  355. cv::String output_info;
  356. EXPECT_TRUE(QRCodeDetector().decodeMulti(resized_src, corners, decoded_info));
  357. for (size_t k = 0; k < decoded_info.size(); ++k)
  358. {
  359. if (!decoded_info[k].empty())
  360. output_info = decoded_info[k];
  361. }
  362. EXPECT_FALSE(output_info.empty())
  363. << "The generated QRcode cannot be decoded." << " Mode: " << modes[i]
  364. << " structures number: " << j;
  365. EXPECT_EQ(input_info, output_info) << "The generated QRcode is not same as test data." << " Mode: " << mode <<
  366. " structures number: " << j;
  367. }
  368. }
  369. }
  370. #endif // UPDATE_QRCODE_TEST_DATA
  371. CV_ENUM(EncodeModes, QRCodeEncoder::EncodeMode::MODE_NUMERIC,
  372. QRCodeEncoder::EncodeMode::MODE_ALPHANUMERIC,
  373. QRCodeEncoder::EncodeMode::MODE_BYTE)
  374. typedef ::testing::TestWithParam<EncodeModes> Objdetect_QRCode_Encode_Decode_Structured_Append_Parameterized;
  375. TEST_P(Objdetect_QRCode_Encode_Decode_Structured_Append_Parameterized, regression_22205)
  376. {
  377. const std::string input_data = "the quick brown fox jumps over the lazy dog";
  378. std::vector<cv::Mat> result_qrcodes;
  379. cv::QRCodeEncoder::Params params;
  380. int encode_mode = GetParam();
  381. params.mode = static_cast<cv::QRCodeEncoder::EncodeMode>(encode_mode);
  382. for(size_t struct_num = 2; struct_num < 5; ++struct_num)
  383. {
  384. params.structure_number = static_cast<int>(struct_num);
  385. cv::Ptr<cv::QRCodeEncoder> encoder = cv::QRCodeEncoder::create(params);
  386. encoder->encodeStructuredAppend(input_data, result_qrcodes);
  387. EXPECT_EQ(result_qrcodes.size(), struct_num) << "The number of QR Codes requested is not equal"<<
  388. "to the one returned";
  389. }
  390. }
  391. INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Encode_Decode_Structured_Append_Parameterized, EncodeModes::all());
  392. TEST(Objdetect_QRCode_Encode_Decode, regression_issue22029)
  393. {
  394. const cv::String msg = "OpenCV";
  395. const int min_version = 1;
  396. const int max_version = 40;
  397. for ( int v = min_version ; v <= max_version ; v++ )
  398. {
  399. SCOPED_TRACE(cv::format("version=%d",v));
  400. Mat qrimg;
  401. QRCodeEncoder::Params params;
  402. params.version = v;
  403. Ptr<QRCodeEncoder> qrcode_enc = cv::QRCodeEncoder::create(params);
  404. qrcode_enc->encode(msg, qrimg);
  405. const int white_margin = 2;
  406. const int finder_width = 7;
  407. const int timing_pos = white_margin + 6;
  408. int i;
  409. // Horizontal Check
  410. // (1) White margin(Left)
  411. for(i = 0; i < white_margin ; i++ )
  412. {
  413. ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
  414. }
  415. // (2) Finder pattern(Left)
  416. for( ; i < white_margin + finder_width ; i++ )
  417. {
  418. ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
  419. }
  420. // (3) Timing pattern
  421. for( ; i < qrimg.rows - finder_width - white_margin; i++ )
  422. {
  423. ASSERT_EQ((uint8_t)(i % 2 == 0)?0:255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
  424. }
  425. // (4) Finder pattern(Right)
  426. for( ; i < qrimg.rows - white_margin; i++ )
  427. {
  428. ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
  429. }
  430. // (5) White margin(Right)
  431. for( ; i < qrimg.rows ; i++ )
  432. {
  433. ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
  434. }
  435. // Vertical Check
  436. // (1) White margin(Top)
  437. for(i = 0; i < white_margin ; i++ )
  438. {
  439. ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
  440. }
  441. // (2) Finder pattern(Top)
  442. for( ; i < white_margin + finder_width ; i++ )
  443. {
  444. ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
  445. }
  446. // (3) Timing pattern
  447. for( ; i < qrimg.rows - finder_width - white_margin; i++ )
  448. {
  449. ASSERT_EQ((uint8_t)(i % 2 == 0)?0:255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
  450. }
  451. // (4) Finder pattern(Bottom)
  452. for( ; i < qrimg.rows - white_margin; i++ )
  453. {
  454. ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
  455. }
  456. // (5) White margin(Bottom)
  457. for( ; i < qrimg.rows ; i++ )
  458. {
  459. ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
  460. }
  461. }
  462. }
  463. // This test reproduces issue https://github.com/opencv/opencv/issues/24366 only in a loop
  464. TEST(Objdetect_QRCode_Encode_Decode, auto_version_pick)
  465. {
  466. cv::QRCodeEncoder::Params params;
  467. params.correction_level = cv::QRCodeEncoder::CORRECT_LEVEL_L;
  468. params.mode = cv::QRCodeEncoder::EncodeMode::MODE_AUTO;
  469. cv::Ptr<cv::QRCodeEncoder> encoder = cv::QRCodeEncoder::create(params);
  470. for (int len = 1; len < 19; len++) {
  471. std::string input;
  472. input.resize(len);
  473. cv::randu(Mat(1, len, CV_8U, &input[0]), 'a', 'z' + 1);
  474. cv::Mat qrcode;
  475. encoder->encode(input, qrcode);
  476. }
  477. }
  478. // Test two QR codes which error correction procedure requires more number of
  479. // syndroms that described in the ISO/IEC 18004
  480. typedef testing::TestWithParam<std::pair<std::string, std::string>> Objdetect_QRCode_decoding;
  481. TEST_P(Objdetect_QRCode_decoding, error_correction)
  482. {
  483. const std::string filename = get<0>(GetParam());
  484. const std::string expected = get<1>(GetParam());
  485. QRCodeDetector qrcode;
  486. cv::String decoded_msg;
  487. Mat src = cv::imread(findDataFile("qrcode/" + filename), IMREAD_GRAYSCALE);
  488. std::vector<Point2f> corners(4);
  489. corners[0] = Point2f(0, 0);
  490. corners[1] = Point2f(src.cols * 1.0f, 0);
  491. corners[2] = Point2f(src.cols * 1.0f, src.rows * 1.0f);
  492. corners[3] = Point2f(0, src.rows * 1.0f);
  493. Mat resized_src;
  494. resize(src, resized_src, fixed_size, 0, 0, INTER_AREA);
  495. float width_ratio = resized_src.cols * 1.0f / src.cols;
  496. float height_ratio = resized_src.rows * 1.0f / src.rows;
  497. for(size_t m = 0; m < corners.size(); m++)
  498. {
  499. corners[m].x = corners[m].x * width_ratio;
  500. corners[m].y = corners[m].y * height_ratio;
  501. }
  502. Mat straight_barcode;
  503. EXPECT_NO_THROW(decoded_msg = qrcode.decode(resized_src, corners, straight_barcode));
  504. ASSERT_FALSE(straight_barcode.empty()) << "Can't decode qrimage " << filename;
  505. EXPECT_EQ(expected, decoded_msg);
  506. }
  507. INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_decoding, testing::ValuesIn(std::vector<std::pair<std::string, std::string>>{
  508. {"err_correct_1M.png", "New"},
  509. {"err_correct_2L.png", "Version 2 QR Code Test Image"},
  510. }));
  511. TEST(Objdetect_QRCode_Encode_Decode_Long_Text, regression_issue27183)
  512. {
  513. const int len = 135;
  514. Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create();
  515. std::string input;
  516. input.resize(len);
  517. cv::randu(Mat(1, len, CV_8U, &input[0]), 'a', 'z' + 1);
  518. Mat qrcode;
  519. encoder->encode(input, qrcode);
  520. std::vector<Point2f> corners(4);
  521. corners[0] = Point2f(border_width, border_width);
  522. corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
  523. corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
  524. corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
  525. Mat resized_src;
  526. resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
  527. float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
  528. float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
  529. for(size_t j = 0; j < corners.size(); j++)
  530. {
  531. corners[j].x = corners[j].x * width_ratio;
  532. corners[j].y = corners[j].y * height_ratio;
  533. }
  534. QRCodeDetector detector;
  535. cv::String decoded_msg;
  536. Mat straight_barcode;
  537. EXPECT_NO_THROW(decoded_msg = detector.decode(resized_src, corners, straight_barcode));
  538. ASSERT_FALSE(straight_barcode.empty());
  539. EXPECT_EQ(input, decoded_msg);
  540. }
  541. }} // namespace