1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 07:13:02 +04:00

Merge pull request #24299 from dkurt:qrcode_decode

In-house QR codes decoding #24299

### Pull Request Readiness Checklist

QR codes decoding pipeline without 3rdparty dependency (Quirc library). Implemented according to standard https://github.com/yansikeim/QR-Code/blob/master/ISO%20IEC%2018004%202015%20Standard.pdf

**Merge with extra**: https://github.com/opencv/opencv_extra/pull/1124

resolves https://github.com/opencv/opencv/issues/24225
resolves https://github.com/opencv/opencv/issues/17290
resolves https://github.com/opencv/opencv/issues/24318 https://github.com/opencv/opencv/issues/24346

Resources:
* https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders
* https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm

```
Geometric mean (ms)

                                   Name of Test                                      quirc   new2      new2   
                                                                                                        vs    
                                                                                                      quirc   
                                                                                                    (x-factor)
decode::Perf_Objdetect_Not_QRCode::("chessboard", 640x480)                           9.151   9.157     1.00   
decode::Perf_Objdetect_Not_QRCode::("chessboard", 1280x720)                         21.609  21.609     1.00   
decode::Perf_Objdetect_Not_QRCode::("chessboard", 1920x1080)                        42.088  41.924     1.00   
decode::Perf_Objdetect_Not_QRCode::("chessboard", 3840x2160)                        169.737 169.050    1.00   
decode::Perf_Objdetect_Not_QRCode::("random", 640x480)                               8.552   8.611     0.99   
decode::Perf_Objdetect_Not_QRCode::("random", 1280x720)                             21.264  21.581     0.99   
decode::Perf_Objdetect_Not_QRCode::("random", 1920x1080)                            42.415  43.468     0.98   
decode::Perf_Objdetect_Not_QRCode::("random", 3840x2160)                            175.003 174.294    1.00   
decode::Perf_Objdetect_Not_QRCode::("zero", 640x480)                                 8.528   8.421     1.01   
decode::Perf_Objdetect_Not_QRCode::("zero", 1280x720)                               21.548  21.209     1.02   
decode::Perf_Objdetect_Not_QRCode::("zero", 1920x1080)                              42.581  42.529     1.00   
decode::Perf_Objdetect_Not_QRCode::("zero", 3840x2160)                              176.231 174.410    1.01   
decode::Perf_Objdetect_QRCode::"kanji.jpg"                                           6.105   6.072     1.01   
decode::Perf_Objdetect_QRCode::"link_github_ocv.jpg"                                 6.069   6.076     1.00   
decode::Perf_Objdetect_QRCode::"link_ocv.jpg"                                        6.143   6.240     0.98   
decode::Perf_Objdetect_QRCode::"link_wiki_cv.jpg"                                    6.369   6.420     0.99   
decode::Perf_Objdetect_QRCode::"russian.jpg"                                         6.558   6.549     1.00   
decode::Perf_Objdetect_QRCode::"version_1_down.jpg"                                  5.634   5.621     1.00   
decode::Perf_Objdetect_QRCode::"version_1_left.jpg"                                  5.560   5.609     0.99   
decode::Perf_Objdetect_QRCode::"version_1_right.jpg"                                 5.539   5.631     0.98   
decode::Perf_Objdetect_QRCode::"version_1_top.jpg"                                   5.622   5.566     1.01   
decode::Perf_Objdetect_QRCode::"version_1_up.jpg"                                    5.569   5.534     1.01   
decode::Perf_Objdetect_QRCode::"version_5_down.jpg"                                  6.514   6.436     1.01   
decode::Perf_Objdetect_QRCode::"version_5_left.jpg"                                  6.668   6.479     1.03   
decode::Perf_Objdetect_QRCode::"version_5_top.jpg"                                   6.481   6.484     1.00   
decode::Perf_Objdetect_QRCode::"version_5_up.jpg"                                    7.011   6.513     1.08   
decodeMulti::Perf_Objdetect_QRCode_Multi::("2_qrcodes.png", "aruco_based")          14.885  15.089     0.99   
decodeMulti::Perf_Objdetect_QRCode_Multi::("2_qrcodes.png", "contours_based")       14.896  14.906     1.00   
decodeMulti::Perf_Objdetect_QRCode_Multi::("3_close_qrcodes.png", "aruco_based")     6.661   6.663     1.00   
decodeMulti::Perf_Objdetect_QRCode_Multi::("3_close_qrcodes.png", "contours_based")  6.614   6.592     1.00   
decodeMulti::Perf_Objdetect_QRCode_Multi::("3_qrcodes.png", "aruco_based")          14.814  14.592     1.02   
decodeMulti::Perf_Objdetect_QRCode_Multi::("3_qrcodes.png", "contours_based")       15.245  15.135     1.01   
decodeMulti::Perf_Objdetect_QRCode_Multi::("4_qrcodes.png", "aruco_based")          10.923  10.881     1.00   
decodeMulti::Perf_Objdetect_QRCode_Multi::("4_qrcodes.png", "contours_based")       10.680  10.128     1.05   
decodeMulti::Perf_Objdetect_QRCode_Multi::("5_qrcodes.png", "contours_based")       11.788  11.576     1.02   
decodeMulti::Perf_Objdetect_QRCode_Multi::("6_qrcodes.png", "aruco_based")          25.887  25.979     1.00   
decodeMulti::Perf_Objdetect_QRCode_Multi::("6_qrcodes.png", "contours_based")       26.183  25.627     1.02   
decodeMulti::Perf_Objdetect_QRCode_Multi::("7_qrcodes.png", "aruco_based")          32.786  32.253     1.02   
decodeMulti::Perf_Objdetect_QRCode_Multi::("7_qrcodes.png", "contours_based")       24.290  24.435     0.99   
decodeMulti::Perf_Objdetect_QRCode_Multi::("8_close_qrcodes.png", "aruco_based")    89.696  89.247     1.01   
decodeMulti::Perf_Objdetect_QRCode_Multi::("8_close_qrcodes.png", "contours_based") 89.872  89.600     1.00
```
This commit is contained in:
Dmitry Kurtaev
2023-11-24 11:35:36 +03:00
committed by GitHub
parent 332748dd55
commit d296d29a1c
10 changed files with 656 additions and 151 deletions
+38 -12
View File
@@ -118,9 +118,7 @@ TEST(Objdetect_QRCode_Encode, generate_test_data)
}
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 << "}";
}
@@ -306,7 +304,6 @@ TEST(Objdetect_QRCode_Encode_Decode, regression)
corners[k].y = corners[k].y * height_ratio;
}
#ifdef HAVE_QUIRC
Mat straight_barcode;
std::string output_info = QRCodeDetector().decode(resized_src, corners, straight_barcode);
EXPECT_FALSE(output_info.empty())
@@ -314,7 +311,6 @@ TEST(Objdetect_QRCode_Encode_Decode, regression)
<< " version: " << version << " error correction level: " << (int)level;
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;
#endif
}
}
}
@@ -356,12 +352,10 @@ TEST(Objdetect_QRCode_Encode_Kanji, regression)
corners[j].y = corners[j].y * height_ratio;
}
#ifdef HAVE_QUIRC
Mat straight_barcode;
std::string decoded_info = QRCodeDetector().decode(resized_src, corners, straight_barcode);
EXPECT_FALSE(decoded_info.empty()) << "The generated QRcode cannot be decoded.";
EXPECT_EQ(input_info, decoded_info);
#endif
}
}
@@ -423,21 +417,15 @@ TEST(Objdetect_QRCode_Encode_Decode_Structured_Append, DISABLED_regression)
corners[m].y = corners[m].y * height_ratio;
}
#ifdef HAVE_QUIRC
Mat straight_barcode;
std::string decoded_info = QRCodeDetector().decode(resized_src, corners, straight_barcode);
EXPECT_FALSE(decoded_info.empty())
<< "The generated QRcode cannot be decoded." << " Mode: " << modes[i]
<< " structures number: " << k << "/" << j;
output_info += decoded_info;
#endif
}
#ifdef HAVE_QUIRC
EXPECT_EQ(input_info, output_info) << "The generated QRcode is not same as test data." << " Mode: " << mode <<
" structures number: " << j;
#else
std::cout << "Mode=" << mode << ": Unable to verify generated QR codes - QUIRC is disabled" << std::endl;
#endif
}
}
}
@@ -566,4 +554,42 @@ TEST(Objdetect_QRCode_Encode_Decode, auto_version_pick)
}
}
// Test two QR codes which error correction procedure requires more number of
// syndroms that described in the ISO/IEC 18004
typedef testing::TestWithParam<std::pair<std::string, std::string>> Objdetect_QRCode_decoding;
TEST_P(Objdetect_QRCode_decoding, error_correction)
{
const std::string filename = get<0>(GetParam());
const std::string expected = get<1>(GetParam());
QRCodeDetector qrcode;
cv::String decoded_msg;
Mat src = cv::imread(findDataFile("qrcode/" + filename), IMREAD_GRAYSCALE);
std::vector<Point2f> corners(4);
corners[0] = Point2f(0, 0);
corners[1] = Point2f(src.cols * 1.0f, 0);
corners[2] = Point2f(src.cols * 1.0f, src.rows * 1.0f);
corners[3] = Point2f(0, src.rows * 1.0f);
Mat resized_src;
resize(src, resized_src, fixed_size, 0, 0, INTER_AREA);
float width_ratio = resized_src.cols * 1.0f / src.cols;
float height_ratio = resized_src.rows * 1.0f / src.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;
}
Mat straight_barcode;
EXPECT_NO_THROW(decoded_msg = qrcode.decode(resized_src, corners, straight_barcode));
ASSERT_FALSE(straight_barcode.empty()) << "Can't decode qrimage " << filename;
EXPECT_EQ(expected, decoded_msg);
}
INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_decoding, testing::ValuesIn(std::vector<std::pair<std::string, std::string>>{
{"err_correct_1M.png", "New"},
{"err_correct_2L.png", "Version 2 QR Code Test Image"},
}));
}} // namespace