diff --git a/modules/wechat_qrcode/src/decodermgr.cpp b/modules/wechat_qrcode/src/decodermgr.cpp index 06706eed2..d4b8edf6f 100644 --- a/modules/wechat_qrcode/src/decodermgr.cpp +++ b/modules/wechat_qrcode/src/decodermgr.cpp @@ -18,7 +18,7 @@ using zxing::Result; using zxing::UnicomBlock; namespace cv { namespace wechat_qrcode { -int DecoderMgr::decodeImage(cv::Mat src, bool use_nn_detector, string& result) { +int DecoderMgr::decodeImage(cv::Mat src, bool use_nn_detector, string& result, vector& points) { int width = src.cols; int height = src.rows; if (width <= 20 || height <= 20) @@ -46,6 +46,14 @@ int DecoderMgr::decodeImage(cv::Mat src, bool use_nn_detector, string& result) { int ret = TryDecode(source, zx_result); if (!ret) { result = zx_result->getText()->getText(); + auto result_points = zx_result->getResultPoints(); + for(int i = 0; i < result_points->size() / 4; i++) { + const int ind = i * 4; + for (int j = 1; j < 4; j++) + points.emplace_back(result_points[ind+j]->getX(), result_points[ind+j]->getY()); + + points.emplace_back(result_points[ind]->getX(), result_points[ind]->getY()); + } return ret; } // try different binarizers diff --git a/modules/wechat_qrcode/src/decodermgr.hpp b/modules/wechat_qrcode/src/decodermgr.hpp index 10ac16e7c..c2f29dbe2 100644 --- a/modules/wechat_qrcode/src/decodermgr.hpp +++ b/modules/wechat_qrcode/src/decodermgr.hpp @@ -26,7 +26,7 @@ public: DecoderMgr() { reader_ = new zxing::qrcode::QRCodeReader(); }; ~DecoderMgr(){}; - int decodeImage(cv::Mat src, bool use_nn_detector, string& result); + int decodeImage(cv::Mat src, bool use_nn_detector, string& result, vector& points); private: zxing::Ref qbarUicomBlock_; diff --git a/modules/wechat_qrcode/src/wechat_qrcode.cpp b/modules/wechat_qrcode/src/wechat_qrcode.cpp index df5e8bbcc..774527941 100644 --- a/modules/wechat_qrcode/src/wechat_qrcode.cpp +++ b/modules/wechat_qrcode/src/wechat_qrcode.cpp @@ -131,8 +131,8 @@ vector WeChatQRCode::Impl::decode(const Mat& img, vector& candidate vector decode_results; for (auto& point : candidate_points) { Mat cropped_img; + Align aligner; if (use_nn_detector_) { - Align aligner; cropped_img = cropObj(img, point, aligner); } else { cropped_img = img; @@ -144,9 +144,19 @@ vector WeChatQRCode::Impl::decode(const Mat& img, vector& candidate super_resolution_model_->processImageScale(cropped_img, cur_scale, use_nn_sr_); string result; DecoderMgr decodemgr; - auto ret = decodemgr.decodeImage(scaled_img, use_nn_detector_, result); - + vector points_qr; + auto ret = decodemgr.decodeImage(scaled_img, use_nn_detector_, result, points_qr); if (ret == 0) { + for (auto&& pt: points_qr) { + pt /= cur_scale; + } + + if (use_nn_detector_) + points_qr = aligner.warpBack(points_qr); + for (int i = 0; i < 4; ++i) { + point.at(i, 0) = points_qr[i].x; + point.at(i, 1) = points_qr[i].y; + } decode_results.push_back(result); points.push_back(point); break; diff --git a/modules/wechat_qrcode/test/test_qrcode.cpp b/modules/wechat_qrcode/test/test_qrcode.cpp index cbd1b2fb3..25ab24895 100644 --- a/modules/wechat_qrcode/test/test_qrcode.cpp +++ b/modules/wechat_qrcode/test/test_qrcode.cpp @@ -284,6 +284,58 @@ TEST_P(Objdetect_QRCode_Multi, regression) { } } +TEST(Objdetect_QRCode_points_position, rotate45) { + string path_detect_prototxt, path_detect_caffemodel, path_sr_prototxt, path_sr_caffemodel; + string model_version = "_2021-01"; + path_detect_prototxt = findDataFile("dnn/wechat"+model_version+"/detect.prototxt", false); + path_detect_caffemodel = findDataFile("dnn/wechat"+model_version+"/detect.caffemodel", false); + path_sr_prototxt = findDataFile("dnn/wechat"+model_version+"/sr.prototxt", false); + path_sr_caffemodel = findDataFile("dnn/wechat"+model_version+"/sr.caffemodel", false); + + auto detector = wechat_qrcode::WeChatQRCode(path_detect_prototxt, path_detect_caffemodel, path_sr_prototxt, + path_sr_caffemodel); + + const cv::String expect_msg = "OpenCV"; + QRCodeEncoder::Params params; + params.version = 5; // 37x37 + Ptr qrcode_enc = cv::QRCodeEncoder::create(params); + Mat qrImage; + qrcode_enc->encode(expect_msg, qrImage); + Mat image(800, 800, CV_8UC1); + const int pixInBlob = 4; + Size qrSize = Size((21+(params.version-1)*4)*pixInBlob,(21+(params.version-1)*4)*pixInBlob); + Rect2f rec((image.cols - qrSize.width)/2, (image.rows - qrSize.height)/2, qrSize.width, qrSize.height); + vector goldCorners = {rec.x, rec.y, + rec.x+rec.width, rec.y, + rec.x+rec.width, rec.y+rec.height, + rec.x, rec.y+rec.height}; + Mat roiImage = image(rec); + cv::resize(qrImage, roiImage, qrSize, 1., 1., INTER_NEAREST); + + vector points1; + auto decoded_info1 = detector.detectAndDecode(image, points1); + ASSERT_EQ(1ull, decoded_info1.size()); + ASSERT_EQ(expect_msg, decoded_info1[0]); + EXPECT_NEAR(0, cvtest::norm(Mat(goldCorners), points1[0].reshape(1, 8), NORM_INF), 8.); + + const double angle = 45; + Point2f pc(image.cols/2.f, image.rows/2.f); + Mat rot = getRotationMatrix2D(pc, angle, 1.); + warpAffine(image, image, rot, image.size()); + vector rotateGoldCorners; + for (int i = 0; i < static_cast(goldCorners.size()); i+= 2) { + rotateGoldCorners.push_back(rot.at(0, 0) * goldCorners[i] + + rot.at(0, 1) * goldCorners[i+1] + rot.at(0, 2)); + rotateGoldCorners.push_back(rot.at(1, 0) * goldCorners[i] + + rot.at(1, 1) * goldCorners[i+1] + rot.at(1, 2)); + } + vector points2; + auto decoded_info2 = detector.detectAndDecode(image, points2); + ASSERT_EQ(1ull, decoded_info2.size()); + ASSERT_EQ(expect_msg, decoded_info2[0]); + EXPECT_NEAR(0, cvtest::norm(Mat(rotateGoldCorners), points2[0].reshape(1, 8), NORM_INF), 11.); +} + INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode, testing::ValuesIn(qrcode_images_name)); INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Close, testing::ValuesIn(qrcode_images_close)); INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Monitor, testing::ValuesIn(qrcode_images_monitor));