提交 3da69a26 编写于 作者: M MaoXianxin

微信二维码引擎OpenCV开源!3行代码让你拥有微信扫码能力

上级 fa20555d
1.png

193.2 KB | W: | H:

1.png

186.0 KB | W: | H:

1.png
1.png
1.png
1.png
  • 2-up
  • Swipe
  • Onion skin
# OpenCV中单目标跟踪算法DaSiamRPN的C++实现
# 微信二维码引擎OpenCV开源!3行代码让你拥有微信扫码能力
**每天会对文章进行更新,每次更新一篇,采用阅后即焚模式,且看且珍惜,喜欢的话帮我点个star哈**
单目标跟踪是计算机视觉中的一个基本问题。在如今深度学习时代也涌现出多种基于深度学习的单目标跟踪算法,其中基于SiamFC(双流网络)的单目标跟踪算法占据了半壁江山。DaSiamRPN就是典型的基于SiamFC的方法
2011年12月微信3.5版本正式上线“扫一扫”二维码,历经9年蜕变,“扫一扫”从二维码名片到扫码支付、从小程序码到健康码,二维码已经成为一种生活方式,连接着数字与现实
GSoC 2020为OpenCV增加了Python版本的DaSiamRPN,后来发现大家对C++版本的需求挺强烈的,于是我就为OpenCV贡献了一个C++版本的DaSiamRPN。
现在,在腾讯WeChatCV团队的贡献下,微信扫码引擎正式加入OpenCV开源了!只需3行代码,你便轻松拥有微信的扫码能力:
对于DaSiamRPN,在inference阶段,模型的主要结构如下图所示:
```
import cv2
detector = cv2.wechat_qrcode_WeChatQRCode("detect.prototxt", "detect.caffemodel", "sr.prototxt", "sr.caffemodel")
img = cv2.imread("img.jpg")
res, points = detector.detectAndDecode(img)
print(res, points)
```
微信扫码引擎收录于:
opencv_contrib/modules/wechat_qrcode
开发文档:
[https://docs.opencv.org/master/d5/d04/classcv_1_1wechat__qrcode_1_1WeChatQRCode.html](https://docs.opencv.org/master/d5/d04/classcv_1_1wechat__qrcode_1_1WeChatQRCode.html)
微信扫码引擎是一款基于开源引擎ZXing,并高度优化和深度改造的高性能轻量二维码识别器。
## 基于CNN的二维码检测
**“一图多码**”是扫码支付经常遇到的线下场景。早在2016年,微信扫码引擎在业内率先支持远距离二维码检测、自动调焦定位、多码检测识别。然而,传统方法需要牺牲40%以上的性能来支持多码的检测与识别。伴随着深度学习技术的成熟和移动端计算能力的提升,微信扫码引擎引入基于CNN的二维码检测器解决上述问题。
![](imgs/1.png)
其中**黄色的CNN网络****橙色的Conv网络**是模型文件,DaSiamRPN最后的输出有两个分别为分类分支:17 x 17 x 2k 和 回归分支:17 x 17 x 4k。
图1 二维码检测器
在实际代码中我们将上图中的模型整合成三个模型:siamRPN,siamKernelCL1,siamKernelR1。其中siamRPN是主要模型,会在每一帧的跟踪中用到,而siamKernelCL1和siamKernelR1仅会在设定模板参数时用到。注意:图中的两个黄色的CNN是公用参数的,详细介绍请看原文[1]
我们以SSD框架为基础,构造了短小精干的二维码检测器(图1),采用残差连接(Residual Concat)、深度卷积(Depthwise Convolution)、空洞卷积(Dilated Convolution)、卷积投影(Convolution Projection)等技术进行了针对性的优化。**整个模型大小仅943KB**,iPhone7(A10)单CPU的推理时间仅需20ms,很好地满足“低延时、小体积、高召回”的业务需求
C++版本使用了与Python版本同样的逻辑和模型文件,下面简单介绍一下实现的主要逻辑。
检测代码:
在单目标跟踪中,首先需要设定模板参数,如以下代码所示:
[https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L156](https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L156)
```
siamRPN.setInput(blob); // blob 为输入的template
Mat out1;
siamRPN.forward(out1, "63"); // 63层的输出为文中描述的黄色CNN的输出
siamKernelCL1.setInput(out1); // 分别作为回归和分类分支的输入
siamKernelR1.setInput(out1);
Mat cls1 = siamKernelCL1.forward(); // 获取模板分类分支的特征
Mat r1 = siamKernelR1.forward(); // 获取模板回归分支的特征
std::vector<int> r1_shape = { 20, 256, 4, 4 }, cls1_shape = { 10, 256, 4, 4 };
siamRPN.setParam(siamRPN.getLayerId("65"), 0, r1.reshape(0, r1_shape)); // 将获取到的参数写入主模型
siamRPN.setParam(siamRPN.getLayerId("68"), 0, cls1.reshape(0, cls1_shape));
```
模型文件:
设定模板参数之后进入跟踪主循环:
[https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/detect.prototxt](https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/detect.prototxt)
```
// 主循环
for (int count = 0; ; ++count)
{
cap >> image;
// ...
float score = trackerEval(image, trackState, siamRPN); // 每一帧的跟踪计算
// 绘制图像
Rect rect = {
int(trackState.targetBox.x - int(trackState.targetBox.width / 2)),
int(trackState.targetBox.y - int(trackState.targetBox.height / 2)),
int(trackState.targetBox.width),
int(trackState.targetBox.height)
};
Mat render_image = image.clone();
rectangle(render_image, rect, Scalar(0, 255, 0), 2);
// ...
imshow(winName, render_image);
int c = waitKey(1);
if (c == 27 /*ESC*/)
break;
}
```
参数文件:
其中上述的`trackerEval`函数即为跟踪目标的计算,主体如下所示:
[https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/detect.caffemodel](https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/detect.caffemodel)
```
float trackerEval(Mat img, trackerConfig& trackState, Net& siamRPN)
{
// 第一步:确认搜索区域。跟踪算法根据前一帧中目标位置确定搜索区域
float searchSize = float((trackState.instanceSize - trackState.exemplarSize) / 2);
float pad = searchSize / scaleZ;
float sx = sz + 2 * pad;
Mat xCrop = getSubwindow(img, targetBox, (float)cvRound(sx), trackState.avgChans);
static Mat blob;
std::vector<Mat> outs;
std::vector<String> outNames;
Mat delta, score;
Mat sc, rc, penalty, pscore;
// 第二步:用siamRPN网络推理
blobFromImage(xCrop, blob, 1.0, Size(trackState.instanceSize, trackState.instanceSize), Scalar(), trackState.swapRB, false, CV_32F);
siamRPN.setInput(blob);
outNames = siamRPN.getUnconnectedOutLayersNames();
siamRPN.forward(outs, outNames);
delta = outs[0];
score = outs[1];
// score 和 delta即为文章开头结构图中的两个输出矩阵
score = score.reshape(0, { 2, trackState.anchorNum, trackState.scoreSize, trackState.scoreSize });
delta = delta.reshape(0, { 4, trackState.anchorNum, trackState.scoreSize, trackState.scoreSize });
// 第三步:后处理
// ...太长,这里省略
return score.at<float>(bestID); // 返回最好的跟踪框
}
```
## 基于CNN的二维码增强
“大图小码”是远距扫码和长按识码经常面临的难点,二维码增强技术可以让小码更加清晰。2014年,微信率先在对话中上线“识别图中二维码”能力,离不开增强技术的加持。在长按识别的场景中,二维码图像经过用户的裁剪、压缩、转发,图像质量严重受损,分辨率急剧下降,边缘变得模糊不清,这给扫码引擎的识别带来了极大的挑战。
传统图像增强算法很难完美地解决以上问题,因此微信扫码引擎率先在识别流程中引入了基于深度学习的超分辨率技术(图2)。在网络结构上,密集连接(Dense Concat)、深度卷积(Depthwise Convolution)、反向卷积(Deconvolution)、残差学习(Residual Learning)等技术改善模型的性能;在目标函数上,针对二维码强边缘和二值化的特点,结合L2/L1损失、边界加权、二值约束设计了针对二维码的目标函数。经过精心的调优,**超分辨率模型大小仅23KB**,在iPhone7(A10)单CPU的推理时间仅需6ms(100x100超分200x200),完全满足移动端的应用需求。
![](C:\Users\My104\Downloads\opencv_technology\imgs\2.png)
超分代码:[https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L68](https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L68)
运行效果:
模型文件:[https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.prototxt](https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.prototxt)
![](imgs/2.png)
参数文件:[https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.caffemodel](https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.caffemodel)
算法存在的问题:模型训练集中包含的小物体较少,该算法在目标为小物体情况下的性能较弱,只能重新训练解决这个问题。
## 更鲁棒的定位点检测
全部代码请参考:[https://github.com/opencv/opencv/blob/master/samples/dnn/dasiamrpn_tracker.cpp](https://github.com/opencv/opencv/blob/master/samples/dnn/dasiamrpn_tracker.cpp)
二维码在识别的时候,通常需要根据扫描像素行/列匹配对应比例来寻找定位点(图3)。
参考资料:
![](imgs/3.png)
1. 原始论文:[https://arxiv.org/abs/1808.06048](https://arxiv.org/abs/1808.06048)
图3 二维码定位点
2. 原始PyTorch实现:[https://github.com/foolwood/DaSiamRPN](https://github.com/foolwood/DaSiamRPN)
在定位点检测上,我们提出面积法的定位点检测方法,相比于传统扫描线方法更为鲁棒和高效,有效地避免了误召回和漏召回;在定位点匹配上,特征聚类方法使得扫码引擎可以高效和准确地匹配多个定位点;在图像二值化上,引入多种更为鲁棒的二值化方法,有效地提高解码的成功率。
3. OpenCV中Python实现:[https://github.com/opencv/opencv/blob/master/samples/dnn/dasiamrpn_tracker.py](https://github.com/opencv/opencv/blob/master/samples/dnn/dasiamrpn_tracker.py)
核心代码:[https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L117](https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L117)
![](1.png)
结合传统计算机视觉和深度学习技术,微信扫码引擎解决了一图多码、大图小码、鲁棒解码等业务痛点和技术难点。如今,该引擎在OpenCV上正式开源,期待广大开发者与我们一同打造业内领先的扫码引擎!
imgs/1.png

426.7 KB | W: | H:

imgs/1.png

200.8 KB | W: | H:

imgs/1.png
imgs/1.png
imgs/1.png
imgs/1.png
  • 2-up
  • Swipe
  • Onion skin
imgs/2.png

429.4 KB | W: | H:

imgs/2.png

101.1 KB | W: | H:

imgs/2.png
imgs/2.png
imgs/2.png
imgs/2.png
  • 2-up
  • Swipe
  • Onion skin
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册