Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions modules/wechat_qrcode/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
set(the_description "WeChat QR code Detector")
ocv_define_module(wechat_qrcode opencv_core opencv_imgproc opencv_dnn WRAP java objc python js)

# need to change
set(wechat_qrcode_commit_hash "a8b69ccc738421293254aec5ddb38bd523503252")
set(hash_detect_caffemodel "238e2b2d6f3c18d6c3a30de0c31e23cf")
set(hash_detect_prototxt "6fb4976b32695f9f5c6305c19f12537d")
set(hash_sr_caffemodel "cbfcd60361a73beb8c583eea7e8e6664")
set(hash_sr_prototxt "69db99927a70df953b471daaba03fbef")

set(model_types caffemodel prototxt)
set(model_names detect sr)

foreach(model_name ${model_names})
foreach(model_type ${model_types})
ocv_download(FILENAME ${model_name}.${model_type}
HASH ${hash_${model_name}_${model_type}}
URL
"${OPENCV_WECHAT_QRCODE_URL}"
"$ENV{OPENCV_WECHAT_QRCODE_URL}"
"https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/${wechat_qrcode_commit_hash}/"
DESTINATION_DIR "${CMAKE_BINARY_DIR}/downloads/wechat_qrcode"
ID "wechat_qrcode"
RELATIVE_URL
STATUS res)
if(NOT res)
message(WARNING "WeChatQRCode: Can't get ${model_name} ${model_type} file for wechat qrcode.")
endif()
endforeach()
endforeach()
253 changes: 253 additions & 0 deletions modules/wechat_qrcode/LICENSE

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions modules/wechat_qrcode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
WeChat QR code detector for detecting and parsing QR code.
================================================

WeChat QR code detector is a high-performance and lightweight QR code detect and decode library, which is contributed by WeChat Computer Vision Team (WeChatCV). It has been widely used in various Tencent applications, including WeChat, WeCom, QQ, QQ Browser, and so on. There are four primary features of WeChat QR code detector:

1. CNN-based QR code detector. Different from the traditional detector, we introduce a tiny CNN model for multiple code detection. The detector is based on SSD architecture with a MobileNetV2-like backbone, which is run on caffe inference framework.

2. CNN-based QR code enhancement. To improve the performance of tiny QR code, we design a lighten super-resolution CNN model for QR code, called QRSR. Depth-wise convolution, DenseNet concat and deconvolution are the core techniques in the QRSR model.

3. More robust finder pattern detection. Besides traditional horizontal line searching, we propose an area size based finder pattern detection method. we calculate the area size of black and white block to locate the finder pattern by the pre-computed connected cells.

4. Massive engineering optimization. Based on [zing-cpp](https://github.com/glassechidna/zxing-cpp), we conduct massive engineering optimization to boost the decoding success rate, such as trying more binarization methods, supporting N:1:3:1:1 finder pattern detection, finding more alignment pattern, clustering similar size finder pattern, and etc.
62 changes: 62 additions & 0 deletions modules/wechat_qrcode/include/opencv2/wechat_qrcode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.

#ifndef __OPENCV_WECHAT_QRCODE_HPP__
#define __OPENCV_WECHAT_QRCODE_HPP__
#include "opencv2/core.hpp"
/** @defgroup wechat_qrcode WeChat QR code detector for detecting and parsing QR code.
*/
namespace cv {
namespace wechat_qrcode {
//! @addtogroup wechat_qrcode
//! @{
/**
* @brief QRCode includes two CNN-based models:
* A object detection model and a super resolution model.
* Object detection model is applied to detect QRCode with the bounding box.
* super resolution model is applied to zoom in QRCode when it is small.
*
*/
class CV_EXPORTS_W WeChatQRCode {
public:
/**
* @brief Initialize the QRCode.
* Two models are packaged with caffe format.
* Therefore, there are prototxt and caffe model two files.
*
* @param detector_prototxt_path prototxt file path for the detector
* @param detector_caffe_model_path caffe model file path for the detector
* @param super_resolution_prototxt_path prototxt file path for the super resolution model
* @param super_resolution_caffe_model_path caffe file path for the super resolution model
*/
CV_WRAP WeChatQRCode(const std::string& detector_prototxt_path = "",
const std::string& detector_caffe_model_path = "",
const std::string& super_resolution_prototxt_path = "",
const std::string& super_resolution_caffe_model_path = "");
~WeChatQRCode(){};

/**
* @brief Both detects and decodes QR code.
* To simplify the usage, there is a only API: detectAndDecode
*
* @param img supports grayscale or color (BGR) image.
* @param points optional output array of vertices of the found QR code quadrangle. Will be
* empty if not found.
* @return list of decoded string.
*/
CV_WRAP std::vector<std::string> detectAndDecode(InputArray img,
OutputArrayOfArrays points = noArray());

protected:
class Impl;
Ptr<Impl> p;
};

//! @}
} // namespace wechat_qrcode
} // namespace cv
#endif // __OPENCV_WECHAT_QRCODE_HPP__
53 changes: 53 additions & 0 deletions modules/wechat_qrcode/samples/qrcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import cv2
import sys

print(sys.argv[0])
print('A demo program of WeChat QRCode Detector:')
camIdx = -1
if len(sys.argv) > 1:
if sys.argv[1] == "-camera":
camIdx = int(sys.argv[2]) if len(sys.argv)>2 else 0
img = cv2.imread(sys.argv[1])
else:
print(" Usage: " + sys.argv[0] + " <input_image>")
exit(0)

# For python API generator, it follows the template: {module_name}_{class_name},
# so it is a little weird.
# The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
# otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
try:
detector = cv2.wechat_qrcode_WeChatQRCode(
"detect.prototxt", "detect.caffemodel", "sr.prototxt", "sr.caffemodel")
except:
print("---------------------------------------------------------------")
print("Failed to initialize WeChatQRCode.")
print("Please, download 'detector.*' and 'sr.*' from")
print("https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode")
print("and put them into the current directory.")
print("---------------------------------------------------------------")
exit(0)

prevstr = ""

if camIdx < 0:
res, points = detector.detectAndDecode(img)
print(res)
else:
cap = cv2.VideoCapture(camIdx)
while True:
res, img = cap.read()
if img.empty():
break
res, points = detector.detectAndDecode(img)
for t in res:
if t != prevstr:
print(t)
if res:
prevstr = res[-1]
cv2.imshow("image", img)
if cv2.waitKey(30) >= 0:
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
70 changes: 70 additions & 0 deletions modules/wechat_qrcode/samples/qrcode_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

#include <opencv2/wechat_qrcode.hpp>
int main(int argc, char* argv[]) {
cout << endl << argv[0] << endl << endl;
cout << "A demo program of WeChat QRCode Detector: " << endl;

Mat img;
int camIdx = -1;
if (argc > 1) {
bool live = strcmp(argv[1], "-camera") == 0;
if (live) {
camIdx = argc > 2 ? atoi(argv[2]) : 0;
} else {
img = imread(argv[1]);
}
} else {
cout << " Usage: " << argv[0] << " <input_image>" << endl;
return 0;
}
// The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
// otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
Ptr<wechat_qrcode::WeChatQRCode> detector;

try {
detector = makePtr<wechat_qrcode::WeChatQRCode>("detect.prototxt", "detect.caffemodel",
"sr.prototxt", "sr.caffemodel");
} catch (const std::exception& e) {
cout <<
"\n---------------------------------------------------------------\n"
"Failed to initialize WeChatQRCode.\n"
"Please, download 'detector.*' and 'sr.*' from\n"
"https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
"and put them into the current directory.\n"
"---------------------------------------------------------------\n";
cout << e.what() << endl;
return 0;
}
string prevstr = "";
vector<Mat> points;

if (camIdx < 0) {
auto res = detector->detectAndDecode(img, points);
for (const auto& t : res) cout << t << endl;
} else {
VideoCapture cap(camIdx);
for(;;) {
cap >> img;
if (img.empty())
break;
auto res = detector->detectAndDecode(img, points);
for (const auto& t : res) {
if (t != prevstr)
cout << t << endl;
}
if (!res.empty())
prevstr = res.back();
imshow("image", img);
if (waitKey(30) >= 0)
break;
}
}
return 0;
}
70 changes: 70 additions & 0 deletions modules/wechat_qrcode/src/binarizermgr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "precomp.hpp"
#include "binarizermgr.hpp"
#include "imgsource.hpp"


using zxing::Binarizer;
using zxing::LuminanceSource;
namespace cv {
namespace wechat_qrcode {
BinarizerMgr::BinarizerMgr() : m_iNowRotateIndex(0), m_iNextOnceBinarizer(-1) {
m_vecRotateBinarizer.push_back(Hybrid);
m_vecRotateBinarizer.push_back(FastWindow);
m_vecRotateBinarizer.push_back(SimpleAdaptive);
m_vecRotateBinarizer.push_back(AdaptiveThreshold);
}

BinarizerMgr::~BinarizerMgr() {}

zxing::Ref<Binarizer> BinarizerMgr::Binarize(zxing::Ref<LuminanceSource> source) {
BINARIZER binarizerIdx = m_vecRotateBinarizer[m_iNowRotateIndex];
if (m_iNextOnceBinarizer >= 0) {
binarizerIdx = (BINARIZER)m_iNextOnceBinarizer;
}

zxing::Ref<Binarizer> binarizer;
switch (binarizerIdx) {
case Hybrid:
binarizer = new zxing::HybridBinarizer(source);
break;
case FastWindow:
binarizer = new zxing::FastWindowBinarizer(source);
break;
case SimpleAdaptive:
binarizer = new zxing::SimpleAdaptiveBinarizer(source);
break;
case AdaptiveThreshold:
binarizer = new zxing::AdaptiveThresholdMeanBinarizer(source);
break;
default:
binarizer = new zxing::HybridBinarizer(source);
break;
}

return binarizer;
}

void BinarizerMgr::SwitchBinarizer() {
m_iNowRotateIndex = (m_iNowRotateIndex + 1) % m_vecRotateBinarizer.size();
}

int BinarizerMgr::GetCurBinarizer() {
if (m_iNextOnceBinarizer != -1) return m_iNextOnceBinarizer;
return m_vecRotateBinarizer[m_iNowRotateIndex];
}

void BinarizerMgr::SetNextOnceBinarizer(int iBinarizerIndex) {
m_iNextOnceBinarizer = iBinarizerIndex;
}

void BinarizerMgr::SetBinarizer(vector<BINARIZER> vecRotateBinarizer) {
m_vecRotateBinarizer = vecRotateBinarizer;
}
} // namespace wechat_qrcode
} // namespace cv
51 changes: 51 additions & 0 deletions modules/wechat_qrcode/src/binarizermgr.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.

#ifndef __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__
#define __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__

#include "zxing/binarizer.hpp"
#include "zxing/common/binarizer/adaptive_threshold_mean_binarizer.hpp"
#include "zxing/common/counted.hpp"
#include "zxing/common/binarizer/fast_window_binarizer.hpp"
#include "zxing/common/binarizer/hybrid_binarizer.hpp"
#include "zxing/common/binarizer/simple_adaptive_binarizer.hpp"
#include "zxing/zxing.hpp"

namespace cv {
namespace wechat_qrcode {
class BinarizerMgr {
public:
enum BINARIZER {
Hybrid = 0,
FastWindow = 1,
SimpleAdaptive = 2,
AdaptiveThreshold = 3
};

public:
BinarizerMgr();
~BinarizerMgr();

zxing::Ref<zxing::Binarizer> Binarize(zxing::Ref<zxing::LuminanceSource> source);

void SwitchBinarizer();

int GetCurBinarizer();

void SetNextOnceBinarizer(int iBinarizerIndex);

void SetBinarizer(vector<BINARIZER> vecRotateBinarizer);

private:
int m_iNowRotateIndex;
int m_iNextOnceBinarizer;
vector<BINARIZER> m_vecRotateBinarizer;
};
} // namespace wechat_qrcode
} // namespace cv
#endif // __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__
Loading