Merge pull request #17889 from ZhengQiushi:my_3.4

QR code (encoding process)

* add qrcode encoder

* qr encoder fixes

* qr encoder: fix api and realization

* fixed qr encoder, added eci and kanji modes

* trigger CI

* qr encoder constructor fixes

Co-authored-by: APrigarina <ann73617@gmail.com>
This commit is contained in:
Qiushi Zheng 2021-11-16 01:15:39 +08:00 committed by GitHub
parent 8041ab8a61
commit 3e51448ef0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 2624 additions and 0 deletions

View File

@ -670,6 +670,69 @@ public:
void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const; void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const;
}; };
class CV_EXPORTS_W QRCodeEncoder {
protected:
QRCodeEncoder(); // use ::create()
public:
virtual ~QRCodeEncoder();
enum EncodeMode {
MODE_AUTO = -1,
MODE_NUMERIC = 1, // 0b0001
MODE_ALPHANUMERIC = 2, // 0b0010
MODE_BYTE = 4, // 0b0100
MODE_ECI = 7, // 0b0111
MODE_KANJI = 8, // 0b1000
MODE_STRUCTURED_APPEND = 3 // 0b0011
};
enum CorrectionLevel {
CORRECT_LEVEL_L = 0,
CORRECT_LEVEL_M = 1,
CORRECT_LEVEL_Q = 2,
CORRECT_LEVEL_H = 3
};
enum ECIEncodings {
ECI_UTF8 = 26
};
/** @brief QR code encoder parameters.
@param version The optional version of QR code (by default - maximum possible depending on
the length of the string).
@param correction_level The optional level of error correction (by default - the lowest).
@param mode The optional encoding mode - Numeric, Alphanumeric, Byte, Kanji, ECI or Structured Append.
@param structure_number The optional number of QR codes to generate in Structured Append mode.
*/
struct CV_EXPORTS_W_SIMPLE Params
{
CV_WRAP Params();
CV_PROP_RW int version;
CV_PROP_RW CorrectionLevel correction_level;
CV_PROP_RW EncodeMode mode;
CV_PROP_RW int structure_number;
};
/** @brief Constructor
@param parameters QR code encoder parameters QRCodeEncoder::Params
*/
static CV_WRAP
Ptr<QRCodeEncoder> create(const QRCodeEncoder::Params& parameters = QRCodeEncoder::Params());
/** @brief Generates QR code from input string.
@param encoded_info Input string to encode.
@param qrcode Generated QR code.
*/
CV_WRAP virtual void encode(const String& encoded_info, OutputArray qrcode) = 0;
/** @brief Generates QR code from input string in Structured Append mode. The encoded message is splitting over a number of QR codes.
@param encoded_info Input string to encode.
@param qrcodes Vector of generated QR codes.
*/
CV_WRAP virtual void encodeStructuredAppend(const String& encoded_info, OutputArrayOfArrays qrcodes) = 0;
};
class CV_EXPORTS_W QRCodeDetector class CV_EXPORTS_W QRCodeDetector
{ {
public: public:

View File

@ -0,0 +1,3 @@
#ifdef HAVE_OPENCV_OBJDETECT
typedef QRCodeEncoder::Params QRCodeEncoder_Params;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,860 @@
// 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.
//
// Copyright (C) 2021, Intel Corporation, all rights reserved.
//
// This is .hpp file included from qrcode_encoder.cpp
namespace cv {
const int MAX_ALIGNMENT = 7;
const int MODES = 4;
const int ERROR_CORR_LEVELS = 4;
const int MAX_VERSION = 40;
struct BlockParams
{
int ecc_codewords;
int num_blocks_in_G1;
int data_codewords_in_G1;
int num_blocks_in_G2;
int data_codewords_in_G2;
};
struct VersionInfo
{
int total_codewords;
int alignment_pattern[MAX_ALIGNMENT];
BlockParams ecc[ERROR_CORR_LEVELS];
};
/** numeric_mode;
alpha_mode;
byte_mode;
kanji mode;
*/
struct ECLevelCapacity
{
int encoding_modes[MODES];
};
struct CharacterCapacity
{
ECLevelCapacity ec_level[ERROR_CORR_LEVELS];
};
const CharacterCapacity version_capacity_database[MAX_VERSION + 1] =
{
{
{
{0, 1, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
}
},
{
{
{41, 25, 17, 10},
{34, 20, 14, 8},
{27, 16, 11, 7},
{17, 10, 7 , 4}
}
},
{
{
{77, 47, 32, 20},
{63, 38, 26, 16},
{48, 29, 20, 12},
{34, 20, 14, 8}
}
},
{
{
{127, 77, 53, 32},
{101, 61, 42, 26},
{77, 47, 32, 20},
{58, 35, 24, 15}
}
},
{
{
{187, 114, 78, 48},
{149, 90, 62, 38},
{111, 67, 46, 28},
{82, 50, 34, 21}
}
},
{
{
{255, 154, 106, 65},
{202, 122, 84, 52},
{144, 87, 60, 37},
{106, 64, 44, 27}
}
},
{
{
{322, 195, 134, 82},
{255, 154, 106, 65},
{178, 108, 74, 45},
{139, 84 , 58, 36}
}
},
{
{
{370, 224, 154, 95},
{293, 178, 122, 75},
{207, 125, 86, 53},
{154, 93 , 64, 39}
}
},
{
{
{461, 279, 192, 118},
{365, 221, 152, 93},
{259, 157, 108, 66},
{202, 122, 84, 52}
}
},
{
{
{552, 335, 230, 141},
{432, 262, 180, 111},
{312, 189, 130, 80},
{235, 143, 98, 60}
}
},
{
{
{652, 395, 271, 167},
{513, 311, 213, 131},
{364, 221, 151, 93},
{288, 174, 119, 74}
}
},
{
{
{772, 468, 321, 198},
{604, 366, 251, 155},
{427, 259, 177, 109},
{331, 200, 137, 85}
}
},
{
{
{883, 535, 367, 226},
{691, 419, 287, 177},
{489, 296, 203, 125},
{374, 227, 155, 96}
}
},
{
{
{1022, 619, 425, 262},
{796, 483, 331, 204},
{580, 352, 241, 149},
{427, 259, 177, 109}
}
},
{
{
{1101, 667, 458, 282},
{871, 528, 362, 223},
{621, 376, 258, 159},
{468, 283, 194, 120}
}
},
{
{
{1250, 758, 520, 320},
{991, 600, 412, 254},
{703, 426, 292, 180},
{530, 321, 220, 136}
}
},
{
{
{1408, 854, 586, 361},
{1082, 656, 450, 277},
{775, 470, 322, 198},
{602, 365, 250, 154}
}
},
{
{
{1548, 938, 644, 397},
{1212, 734, 504, 310},
{876, 531, 364, 224},
{674, 408, 280, 173}
}
},
{
{
{1725, 1046, 718, 442},
{1346, 816, 560, 345},
{948, 574, 394, 243},
{746, 452, 310, 191}
}
},
{
{
{1903, 1153, 792, 488},
{1500, 909, 624, 384},
{1063, 644, 442, 272},
{813, 493, 338, 208}
}
},
{
{
{2061, 1249, 858, 528},
{1600, 970, 666, 410},
{1159, 702, 482, 297},
{919, 557, 382, 235}
}
},
{
{
{2232, 1352, 929, 572},
{1708, 1035, 711, 438},
{1224, 742, 509, 314},
{969, 587, 403, 248}
}
},
{
{
{2409, 1460, 1003, 618},
{1872, 1134, 779, 480},
{1358, 823, 565, 348},
{1056, 640, 439, 270}
}
},
{
{
{2620, 1588, 1091, 672},
{2059, 1248, 857, 528},
{1468, 890, 611, 376},
{1108, 672, 461, 284}
}
},
{
{
{2812, 1704, 1171, 721},
{2188, 1326, 911, 561},
{1588, 963, 661, 407},
{1228, 744, 511, 315}
}
},
{
{
{3057, 1853, 1273, 784},
{2395, 1451, 997, 614},
{1718, 1041, 715, 440},
{1286, 779, 535, 330}
}
},
{
{
{3283, 1990, 1367, 842},
{2544, 1542, 1059, 652},
{1804, 1094, 751, 462},
{1425, 864, 593, 365}
}
},
{
{
{3517, 2132, 1465, 902},
{2701, 1637, 1125, 692},
{1933, 1172, 805, 496},
{1501, 910, 625, 385}
}
},
{
{
{3669, 2223, 1528, 940},
{2857, 1732, 1190, 732},
{2085, 1263, 868, 534},
{1581, 958, 658, 405}
}
},
{
{
{3909, 2369, 1628, 1002},
{3035, 1839, 1264, 778},
{2181, 1322, 908, 559},
{1677, 1016, 698, 430}
}
},
{
{
{4158, 2520, 1732, 1066},
{3289, 1994, 1370, 843},
{2358, 1429, 982, 604},
{1782, 1080, 742, 457}
}
},
{
{
{4417, 2677, 1840, 1132},
{3486, 2113, 1452, 894},
{2473, 1499, 1030, 634},
{1897, 1150, 790, 486}
}
},
{
{
{4686, 2840, 1952, 1201},
{3693, 2238, 1538, 947},
{2670, 1618, 1112, 684},
{2022, 1226, 842, 518}
}
},
{
{
{4965, 3009, 2068, 1273},
{3909, 2369, 1628, 1002},
{2805, 1700, 1168, 719},
{2157, 1307, 898, 553}
}
},
{
{
{5253, 3183, 2188, 1347},
{4134, 2506, 1722, 1060},
{2949, 1787, 1228, 756},
{2301, 1394, 958 , 590}
}
},
{
{
{5529, 3351, 2303, 1417},
{4343, 2632, 1809, 1113},
{3081, 1867, 1283, 790},
{2361, 1431, 983, 605}
}
},
{
{
{5836, 3537, 2431, 1496},
{4588, 2780, 1911, 1176},
{3244, 1966, 1351, 832},
{2524, 1530, 1051, 647}
}
},
{
{
{6153, 3729, 2563, 1577},
{4775, 2894, 1989, 1224},
{3417, 2071, 1423, 876},
{2625, 1591, 1093, 673}
}
},
{
{
{6479, 3927, 2699, 1661},
{5039, 3054, 2099, 1292},
{3599, 2181, 1499, 923},
{2735, 1658, 1139, 701}
}
},
{
{
{6743, 4087, 2809, 1729},
{5313, 3220, 2213, 1362},
{3791, 2298, 1579, 972},
{2927, 1774, 1219, 750}
}
},
{
{
{7089, 4296, 2953, 1817},
{5596, 3391, 2331, 1435},
{3993, 2420, 1663, 1024},
{3057, 1852, 1273, 784}
}
}
};
const VersionInfo version_info_database[MAX_VERSION + 1] =
{
{ /* Version 0 */
0,
{0, 0, 0, 0, 0, 0, 0},
{
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
}
},
{ /* Version 1 */
26,
{0, 0, 0, 0, 0, 0, 0},
{
{7, 1, 19, 0, 0},
{10, 1, 16, 0, 0},
{13, 1, 13, 0, 0},
{17, 1, 9, 0, 0}
}
},
{ /* Version 2 */
44,
{6, 18, 0, 0, 0, 0, 0},
{
{10, 1, 34, 0, 0},
{16, 1, 28, 0, 0},
{22, 1, 22, 0, 0},
{28, 1, 16, 0, 0}
}
},
{ /* Version 3 */
70,
{6, 22, 0, 0, 0, 0, 0},
{
{15, 1, 55, 0, 0},
{26, 1, 44, 0, 0},
{18, 2, 17, 0, 0},
{22, 2, 13, 0, 0}
}
},
{ /* Version 4 */
100,
{6, 26, 0,0,0,0,0},
{
{20, 1, 80, 0, 0},
{18, 2, 32, 0, 0},
{26, 2, 24, 0, 0},
{16, 4, 9 , 0, 0}
}
},
{ /* Version 5 */
134,
{6, 30, 0, 0, 0, 0, 0},
{
{26, 1, 108, 0, 0},
{24, 2, 43, 0, 0},
{18, 2, 15, 2, 16},
{22, 2, 11, 2, 12}
}
},
{ /* Version 6 */
172,
{6, 34, 0, 0, 0, 0, 0},
{
{18, 2, 68, 0, 0},
{16, 4, 27, 0, 0},
{24, 4, 19, 0, 0},
{28, 4, 15, 0, 0}
}
},
{ /* Version 7 */
196,
{6, 22, 38, 0, 0, 0, 0},
{
{20, 2, 78, 0, 0},
{18, 4, 31, 0, 0},
{18, 2, 14, 4, 15},
{26, 4, 13, 1, 14}
}
},
{ /* Version 8 */
242,
{6, 24, 42, 0, 0, 0, 0},
{
{24, 2, 97, 0, 0},
{22, 2, 38, 2, 39},
{22, 4, 18, 2, 19},
{26, 4, 14, 2, 15}
}
},
{ /* Version 9 */
292,
{6, 26, 46, 0, 0, 0, 0},
{
{30, 2, 116, 0, 0},
{22, 3, 36, 2, 37},
{20, 4, 16, 4, 17},
{24, 4, 12, 4, 13}
}
},
{ /* Version 10 */
346,
{6, 28, 50, 0, 0, 0, 0},
{
{18, 2, 68, 2, 69},
{26, 4, 43, 1, 44},
{24, 6, 19, 2, 20},
{28, 6, 15, 2, 16}
}
},
{ /* Version 11 */
404,
{6, 30, 54, 0, 0, 0, 0},
{
{20, 4, 81, 0, 0},
{30, 1, 50, 4, 51},
{28, 4, 22, 4, 23},
{24, 3, 12, 8, 13}
}
},
{ /* Version 12 */
466,
{6, 32, 58, 0, 0, 0, 0},
{
{24, 2, 92, 2, 93},
{22, 6, 36, 2, 37},
{26, 4, 20, 6, 21},
{28, 7, 14, 4, 15}
}
},
{ /* Version 13 */
532,
{6, 34, 62, 0, 0, 0, 0},
{
{26, 4, 107, 0, 0},
{22, 8, 37, 1, 38},
{24, 8, 20, 4, 21},
{22, 12, 11, 4, 12}
}
},
{ /* Version 14 */
581,
{6, 26, 46, 66, 0, 0, 0},
{
{30, 3, 115, 1, 116},
{24, 4, 40, 5, 41},
{20, 11, 16, 5, 17},
{24, 11, 12, 5, 13}
}
},
{ /* Version 15 */
655,
{6, 26, 48, 70, 0, 0, 0},
{
{22, 5, 87, 1, 88},
{24, 5, 41, 5, 42},
{30, 5, 24, 7, 25},
{24, 11, 12, 7, 13}
}
},
{ /* Version 16 */
733,
{6, 26, 50, 74, 0, 0, 0},
{
{24, 5, 98, 1, 99},
{28, 7, 45, 3, 46},
{24, 15, 19, 2, 20},
{30, 3, 15, 13, 16}
}
},
{ /* Version 17 */
815,
{6, 30, 54, 78, 0, 0, 0},
{
{28, 1, 107, 5, 108},
{28, 10, 46, 1, 47},
{28, 1, 22, 15, 23},
{28, 2, 14, 17, 15}
}
},
{ /* Version 18 */
901,
{6, 30, 56, 82, 0, 0, 0},
{
{30, 5, 120, 1, 121},
{26, 9, 43, 4, 44},
{28, 17, 22, 1, 23},
{28, 2, 14, 19, 15}
}
},
{ /* Version 19 */
991,
{6, 30, 58, 86, 0, 0, 0},
{
{28, 3, 113, 4, 114},
{26, 3, 44, 11, 45},
{26, 17, 21, 4, 22},
{26, 9, 13, 16, 14}
}
},
{ /* Version 20 */
1085,
{6, 34, 62, 90, 0, 0, 0},
{
{28, 3, 107, 5, 108},
{26, 3, 41, 13, 42},
{30, 15, 24, 5, 25},
{28, 15, 15, 10, 16}
}
},
{ /* Version 21 */
1156,
{6, 28, 50, 72, 92, 0, 0},
{
{28, 4, 116, 4, 117},
{26, 17, 42, 0, 0},
{28, 17, 22, 6, 23},
{30, 19, 16, 6, 17}
}
},
{ /* Version 22 */
1258,
{6, 26, 50, 74, 98, 0, 0},
{
{28, 2, 111, 7, 112},
{28, 17, 46, 0, 0},
{30, 7, 24, 16, 25},
{24, 34, 13, 0, 0}
}
},
{ /* Version 23 */
1364,
{6, 30, 54, 78, 102, 0, 0},
{
{30, 4, 121,5, 122},
{28, 4, 47, 14, 48},
{30, 11, 24, 14, 25},
{30, 16, 15, 14, 16}
}
},
{ /* Version 24 */
1474,
{6, 28, 54, 80, 106, 0, 0},
{
{30, 6, 117,4, 118},
{28, 6, 45, 14, 46},
{30, 11, 24, 16, 25},
{30, 30, 16, 2, 17}
}
},
{ /* Version 25 */
1588,
{6, 32, 58, 84, 110, 0, 0},
{
{26, 8, 106, 4, 107},
{28, 8, 47, 13, 48},
{30, 7, 24, 22, 25},
{30, 22, 15, 13, 16}
}
},
{ /* Version 26 */
1706,
{6, 30, 58, 86, 114, 0, 0},
{
{28, 10, 114, 2, 115},
{28, 19, 46, 4, 47},
{28, 28, 22, 6, 23},
{30, 33, 16, 4, 17}
}
},
{ /* Version 27 */
1828,
{6, 34, 62, 90, 118, 0, 0},
{
{30, 8, 122, 4, 123},
{28, 22, 45, 3, 46},
{30, 8, 23, 26, 24},
{30, 12, 15, 28, 16}
}
},
{ /* Version 28 */
1921,
{6, 26, 50, 74, 98, 122, 0},
{
{30, 3, 117, 10, 118},
{28, 3, 45, 23, 46},
{30, 4, 24, 31, 25},
{30, 11, 15, 31, 16}
}
},
{ /* Version 29 */
2051,
{6, 30, 54, 78, 102, 126, 0},
{
{30, 7, 116, 7, 117},
{28, 21, 45, 7, 46},
{30, 1, 23, 37, 24},
{30, 19, 15, 26, 16}
}
},
{ /* Version 30 */
2185,
{6, 26, 52, 78, 104, 130, 0},
{
{30, 5, 115, 10, 116},
{28, 19, 47, 10, 48},
{30, 15, 24, 25, 25},
{30, 23, 15, 25, 16}
}
},
{ /* Version 31 */
2323,
{6, 30, 56, 82, 108, 134, 0},
{
{30, 13, 115, 3, 116},
{28, 2, 46, 29, 47},
{30, 42, 24, 1, 25},
{30, 23, 15, 28, 16}
}
},
{ /* Version 32 */
2465,
{6, 34, 60, 86, 112, 138, 0},
{
{30, 17, 115, 0, 0},
{28, 10, 46, 23, 47},
{30, 10, 24, 35, 25},
{30, 19, 15, 35, 16}
}
},
{ /* Version 33 */
2611,
{6, 30, 58, 86, 114, 142, 0},
{
{30, 17, 115, 1, 116},
{28, 14, 46, 21, 47},
{30, 29, 24, 19, 25},
{30, 11, 15, 46, 16}
}
},
{ /* Version 34 */
2761,
{6, 34, 62, 90, 118, 146, 0},
{
{30, 13, 115, 6, 116},
{28, 14, 46, 23, 47},
{30, 44, 24, 7, 25},
{30, 59, 16, 1, 17}
}
},
{ /* Version 35 */
2876,
{6, 30, 54, 78, 102, 126, 150},
{
{30, 12, 121, 7, 122},
{28, 12, 47, 26, 48},
{30, 39, 24, 14, 25},
{30, 22, 15, 41, 16}
}
},
{ /* Version 36 */
3034,
{6, 24, 50, 76, 102, 128, 154},
{
{30, 6, 121, 14, 122},
{28, 6, 47, 34, 48},
{30, 46, 24, 10, 25},
{30, 2, 15, 64, 16}
}
},
{ /* Version 37 */
3196,
{6, 28, 54, 80, 106, 132, 158},
{
{30, 17, 122, 4, 123},
{28, 29, 46, 14, 47},
{30, 49, 24, 10, 25},
{30, 24, 15, 46, 16}
}
},
{ /* Version 38 */
3362,
{6, 32, 58, 84, 110, 136, 162},
{
{30, 4, 122, 18, 123},
{28, 13, 46, 32, 47},
{30, 48, 24, 14, 25},
{30, 42, 15, 32, 16}
}
},
{ /* Version 39 */
3532,
{6, 26, 54, 82, 110, 138, 166},
{
{30, 20, 117,4, 118},
{28, 40, 47, 7, 48},
{30, 43, 24, 22, 25},
{30, 10, 15, 67, 16}
}
},
{ /* Version 40 */
3706,
{6, 30, 58, 86, 114, 142, 170},
{
{30, 19, 118, 6, 119},
{28, 18, 47, 31, 48},
{30, 34, 24, 34, 25},
{30, 20, 15, 61, 16}
}
}
};
static const uint8_t gf_exp[256] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35,
0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0,
0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f,
0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88,
0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9,
0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa,
0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4,
0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e,
0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5,
0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83,
0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01
};
static const uint8_t gf_log[256] = {
0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
};
}

View File

@ -0,0 +1,433 @@
// 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"
namespace opencv_test { namespace {
std::string encode_qrcode_images_name[] = {
"version1_mode1.png", "version1_mode2.png", "version1_mode4.png",
"version2_mode1.png", "version2_mode2.png", "version2_mode4.png",
"version3_mode2.png", "version3_mode4.png",
"version4_mode4.png"
};
std::string encode_qrcode_eci_images_name[] = {
"version1_mode7.png",
"version2_mode7.png",
"version3_mode7.png",
"version4_mode7.png",
"version5_mode7.png"
};
const Size fixed_size = Size(200, 200);
const float border_width = 2.0;
int establishCapacity(QRCodeEncoder::EncodeMode mode, int version, int capacity)
{
int result = 0;
capacity *= 8;
capacity -= 4;
switch (mode)
{
case QRCodeEncoder::MODE_NUMERIC:
{
if (version >= 10)
capacity -= 12;
else
capacity -= 10;
int tmp = capacity / 10;
result = tmp * 3;
if (tmp * 10 + 7 <= capacity)
result += 2;
else if (tmp * 10 + 4 <= capacity)
result += 1;
break;
}
case QRCodeEncoder::MODE_ALPHANUMERIC:
{
if (version < 10)
capacity -= 9;
else
capacity -= 13;
int tmp = capacity / 11;
result = tmp * 2;
if (tmp * 11 + 6 <= capacity)
result++;
break;
}
case QRCodeEncoder::MODE_BYTE:
{
if (version > 9)
capacity -= 16;
else
capacity -= 8;
result = capacity / 8;
break;
}
default:
break;
}
return result;
}
// #define UPDATE_TEST_DATA
#ifdef UPDATE_TEST_DATA
TEST(Objdetect_QRCode_Encode, generate_test_data)
{
const std::string root = "qrcode/encode";
const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
FileStorage file_config(dataset_config, FileStorage::WRITE);
file_config << "test_images" << "[";
size_t images_count = sizeof(encode_qrcode_images_name) / sizeof(encode_qrcode_images_name[0]);
for (size_t i = 0; i < images_count; i++)
{
file_config << "{:" << "image_name" << encode_qrcode_images_name[i];
std::string image_path = findDataFile(root + "/" + encode_qrcode_images_name[i]);
Mat src = imread(image_path, IMREAD_GRAYSCALE);
Mat straight_barcode;
EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
std::vector<Point2f> corners(4);
corners[0] = Point2f(border_width, border_width);
corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
Mat resized_src;
resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
for(size_t j = 0; j < corners.size(); j++)
{
corners[j].x = corners[j].x * width_ratio;
corners[j].y = corners[j].y * height_ratio;
}
std::string decoded_info = "";
#ifdef HAVE_QUIRC
EXPECT_TRUE(decodeQRCode(resized_src, corners, decoded_info, straight_barcode)) << "The QR code cannot be decoded: " << image_path;
#endif
file_config << "info" << decoded_info;
file_config << "}";
}
file_config << "]";
file_config.release();
}
#else
typedef testing::TestWithParam< std::string > Objdetect_QRCode_Encode;
TEST_P(Objdetect_QRCode_Encode, regression) {
const int pixels_error = 3;
const std::string name_current_image = GetParam();
const std::string root = "qrcode/encode";
std::string image_path = findDataFile(root + "/" + name_current_image);
const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
FileStorage file_config(dataset_config, FileStorage::READ);
ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
{
FileNode images_list = file_config["test_images"];
size_t images_count = static_cast<size_t>(images_list.size());
ASSERT_GT(images_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
for (size_t index = 0; index < images_count; index++)
{
FileNode config = images_list[(int)index];
std::string name_test_image = config["image_name"];
if (name_test_image == name_current_image)
{
std::string original_info = config["info"];
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create();
Mat result;
encoder->encode(original_info, result);
EXPECT_FALSE(result.empty()) << "Can't generate QR code image";
Mat src = imread(image_path, IMREAD_GRAYSCALE);
Mat straight_barcode;
EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
double diff_norm = cvtest::norm(result - src, NORM_L1);
EXPECT_NEAR(diff_norm, 0.0, pixels_error) << "The generated QRcode is not same as test data. The difference: " << diff_norm;
return; // done
}
}
FAIL() << "Not found results in config file:" << dataset_config
<< "\nRe-run tests with enabled UPDATE_ENCODE_TEST_DATA macro to update test data.";
}
}
typedef testing::TestWithParam< std::string > Objdetect_QRCode_Encode_ECI;
TEST_P(Objdetect_QRCode_Encode_ECI, regression) {
const int pixels_error = 3;
const std::string name_current_image = GetParam();
const std::string root = "qrcode/encode";
std::string image_path = findDataFile(root + "/" + name_current_image);
const std::string dataset_config = findDataFile(root + "/" + "dataset_config.json");
FileStorage file_config(dataset_config, FileStorage::READ);
ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
{
FileNode images_list = file_config["test_images"];
size_t images_count = static_cast<size_t>(images_list.size());
ASSERT_GT(images_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
QRCodeEncoder::Params params;
params.mode = QRCodeEncoder::MODE_ECI;
for (size_t index = 0; index < images_count; index++)
{
FileNode config = images_list[(int)index];
std::string name_test_image = config["image_name"];
if (name_test_image == name_current_image)
{
std::string original_info = config["info"];
Mat result;
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
encoder->encode(original_info, result);
EXPECT_FALSE(result.empty()) << "Can't generate QR code image";
Mat src = imread(image_path, IMREAD_GRAYSCALE);
Mat straight_barcode;
EXPECT_TRUE(!src.empty()) << "Can't read image: " << image_path;
double diff_norm = cvtest::norm(result - src, NORM_L1);
EXPECT_NEAR(diff_norm, 0.0, pixels_error) << "The generated QRcode is not same as test data. The difference: " << diff_norm;
return; // done
}
}
FAIL() << "Not found results in config file:" << dataset_config
<< "\nRe-run tests with enabled UPDATE_ENCODE_TEST_DATA macro to update test data.";
}
}
INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Encode, testing::ValuesIn(encode_qrcode_images_name));
INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Encode_ECI, testing::ValuesIn(encode_qrcode_eci_images_name));
TEST(Objdetect_QRCode_Encode_Decode, regression)
{
const std::string root = "qrcode/decode_encode";
const int min_version = 1;
const int test_max_version = 5;
const int max_ec_level = 3;
const std::string dataset_config = findDataFile(root + "/" + "symbol_sets.json");
const std::string version_config = findDataFile(root + "/" + "capacity.json");
FileStorage file_config(dataset_config, FileStorage::READ);
FileStorage capacity_config(version_config, FileStorage::READ);
ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
ASSERT_TRUE(capacity_config.isOpened()) << "Can't read validation data: " << version_config;
FileNode mode_list = file_config["symbols_sets"];
FileNode capacity_list = capacity_config["version_ecc_capacity"];
size_t mode_count = static_cast<size_t>(mode_list.size());
ASSERT_GT(mode_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
const int testing_modes = 3;
QRCodeEncoder::EncodeMode modes[testing_modes] = {
QRCodeEncoder::MODE_NUMERIC,
QRCodeEncoder::MODE_ALPHANUMERIC,
QRCodeEncoder::MODE_BYTE
};
for (int i = 0; i < testing_modes; i++)
{
QRCodeEncoder::EncodeMode mode = modes[i];
FileNode config = mode_list[i];
std::string symbol_set = config["symbols_set"];
for(int version = min_version; version <= test_max_version; version++)
{
FileNode capa_config = capacity_list[version - 1];
for(int level = 0; level <= max_ec_level; level++)
{
const int cur_capacity = capa_config["ecc_level"][level];
int true_capacity = establishCapacity(mode, version, cur_capacity);
std::string input_info = symbol_set;
std::random_shuffle(input_info.begin(),input_info.end());
int count = 0;
if((int)input_info.length() > true_capacity)
{
input_info = input_info.substr(0, true_capacity);
}
else
{
while ((int)input_info.length() != true_capacity)
{
input_info += input_info.substr(count%(int)input_info.length(), 1);
count++;
}
}
QRCodeEncoder::Params params;
params.version = version;
params.correction_level = static_cast<QRCodeEncoder::CorrectionLevel>(level);
params.mode = mode;
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
Mat qrcode;
encoder->encode(input_info, qrcode);
EXPECT_TRUE(!qrcode.empty()) << "Can't generate this QR image (" << "mode: " << (int)mode <<
" version: "<< version <<" error correction level: "<< (int)level <<")";
std::vector<Point2f> corners(4);
corners[0] = Point2f(border_width, border_width);
corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
Mat resized_src;
resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
for(size_t k = 0; k < corners.size(); k++)
{
corners[k].x = corners[k].x * width_ratio;
corners[k].y = corners[k].y * height_ratio;
}
std::string output_info = "";
Mat straight_barcode;
#ifdef HAVE_QUIRC
bool success = decodeQRCode(resized_src, corners, output_info, straight_barcode);
EXPECT_TRUE(success) << "The generated QRcode cannot be decoded." << " Mode: " << (int)mode<<
" version: " << version << " error correction level: " << (int)level;
#endif
EXPECT_EQ(input_info, output_info) << "The generated QRcode is not same as test data." << " Mode: " << (int)mode <<
" version: " << version << " error correction level: " << (int)level;
}
}
}
}
TEST(Objdetect_QRCode_Encode_Kanji, regression)
{
QRCodeEncoder::Params params;
params.mode = QRCodeEncoder::MODE_KANJI;
Mat qrcode;
const int testing_versions = 3;
std::string input_infos[testing_versions] = {"\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x90\xa2\x8a\x45", // こんにちは世界
"\x82\xa8\x95\xa0\x82\xaa\x8b\xf3\x82\xa2\x82\xc4\x82\xa2\x82\xdc\x82\xb7", // お腹が空いています
"\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" // こんにちは、私は少し日本語を話します
};
for (int i = 0; i < testing_versions; i++)
{
std::string input_info = input_infos[i];
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
encoder->encode(input_info, qrcode);
std::vector<Point2f> corners(4);
corners[0] = Point2f(border_width, border_width);
corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
Mat resized_src;
resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
for(size_t j = 0; j < corners.size(); j++)
{
corners[j].x = corners[j].x * width_ratio;
corners[j].y = corners[j].y * height_ratio;
}
Mat straight_barcode;
std::string decoded_info = "";
#ifdef HAVE_QUIRC
EXPECT_TRUE(decodeQRCode(resized_src, corners, decoded_info, straight_barcode)) << "The generated QRcode cannot be decoded.";
#endif
EXPECT_EQ(input_info, decoded_info);
}
}
TEST(Objdetect_QRCode_Encode_Decode_Structured_Append, DISABLED_regression)
{
// disabled since QR decoder probably doesn't support structured append mode qr codes
const std::string root = "qrcode/decode_encode";
const std::string dataset_config = findDataFile(root + "/" + "symbol_sets.json");
const std::string version_config = findDataFile(root + "/" + "capacity.json");
FileStorage file_config(dataset_config, FileStorage::READ);
ASSERT_TRUE(file_config.isOpened()) << "Can't read validation data: " << dataset_config;
FileNode mode_list = file_config["symbols_sets"];
size_t mode_count = static_cast<size_t>(mode_list.size());
ASSERT_GT(mode_count, 0u) << "Can't find validation data entries in 'test_images': " << dataset_config;
int modes[] = {1, 2, 4};
const int min_stuctures_num = 2;
const int max_stuctures_num = 5;
for (int i = 0; i < 3; i++)
{
int mode = modes[i];
FileNode config = mode_list[i];
std::string symbol_set = config["symbols_set"];
std::string input_info = symbol_set;
std::random_shuffle(input_info.begin(), input_info.end());
for (int j = min_stuctures_num; j < max_stuctures_num; j++)
{
QRCodeEncoder::Params params;
params.structure_number = j;
Ptr<QRCodeEncoder> encoder = QRCodeEncoder::create(params);
vector<Mat> qrcodes;
encoder->encodeStructuredAppend(input_info, qrcodes);
EXPECT_TRUE(!qrcodes.empty()) << "Can't generate this QR images";
std::string output_info = "";
for (size_t k = 0; k < qrcodes.size(); k++)
{
Mat qrcode = qrcodes[k];
std::vector<Point2f> corners(4);
corners[0] = Point2f(border_width, border_width);
corners[1] = Point2f(qrcode.cols * 1.0f - border_width, border_width);
corners[2] = Point2f(qrcode.cols * 1.0f - border_width, qrcode.rows * 1.0f - border_width);
corners[3] = Point2f(border_width, qrcode.rows * 1.0f - border_width);
Mat resized_src;
resize(qrcode, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / qrcode.cols;
float height_ratio = resized_src.rows * 1.0f / qrcode.rows;
for(size_t m = 0; m < corners.size(); m++)
{
corners[m].x = corners[m].x * width_ratio;
corners[m].y = corners[m].y * height_ratio;
}
std::string decoded_info = "";
Mat straight_barcode;
#ifdef HAVE_QUIRC
bool success = decodeQRCode(resized_src, corners, decoded_info, straight_barcode);
EXPECT_TRUE(success) << "The generated QRcode cannot be decoded." << " Mode: " << mode <<
" structures number: " << k << "/" << j;
#endif
output_info += decoded_info;
}
EXPECT_EQ(input_info, output_info) << "The generated QRcode is not same as test data." << " Mode: " << mode <<
" structures number: " << j;
}
}
}
#endif // UPDATE_QRCODE_TEST_DATA
}} // namespace