2022-05-23 18:09:48 +08:00

96 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# opencv-js-qrcode
# 纯JS识别照片或图片中的二维码
**场景** 最近在做一个功能,通过识别发票照片获取发票数据用以匹配开票数据存档。
在搜索了各种库踩了一堆坑后发现微信开源过他们的二维码扫码引擎c++版本一阵折腾后编译出js版本整理一下分享出来。本文介绍的方法主要的特点是
* 纯前端处理无须调用后端OCR API等接口
* 可处理标准正方形的二维码,最重要的是可以处理照片上的二维码;二维码变形、旋转都可以识别;
* 基于opencv 编译后的webassembly版本编译添加了微信开源的wechat_qrcode有极高的识别率。
在线测试使用发票照片测试https://leidenglai.github.io/opencv-js-qrcode/
**demo源码: [leidenglai/opencv-js-qrcode · GitHub](https://github.com/leidenglai/opencv-js-qrcode)**
## 加载二维码识别引擎
本文中采用的是自定义编译的opencv库添加了三方组件wechat_qrcode微信二维码引擎并且去掉不需要的库。
开始找了很多”强大的二维码识别库“结果发现基本都不识别照片或者失败率低只能识别标准的qrcode。后来发现c++的opencv并且可编译为wsam版本。由于没有任何c++基础在将wechat_qrcode编译进opencv时异常痛苦好在后来找到一篇blog编译微信二维码引擎到webAssembly实践 | 虚幻 感谢qwertyyb。
在编译好OpenCV后导出opencv.js文件比较大进过优化大约有5
M所以使用时需要异步加载。opencv加载后就能通过window.cv调用到opencv的相关方法此时并不意味着我们能正常运行使用了因为我们还需要加载二维码扫码引擎的模型文件
``` javascript
async function loadModels() {
const detect_proto = "detect.prototxt";
const detect_weight = "detect.caffemodel";
const sr_proto = "sr.prototxt";
const sr_weight = "sr.caffemodel";
if (qrcode_detector != undefined) {
updateStatus("Model Existed");
} else {
const dp = await utils.fetchModelsData(detect_proto);
const dw = await utils.fetchModelsData(detect_weight);
const sp = await utils.fetchModelsData(sr_proto);
const sw = await utils.fetchModelsData(sr_weight);
cv.FS_createDataFile("/", "detect.prototxt", dp, true, false, false);
cv.FS_createDataFile("/", "detect.caffemodel", dw, true, false, false);
cv.FS_createDataFile("/", "sr.prototxt", sp, true, false, false);
cv.FS_createDataFile("/", "sr.caffemodel", sw, true, false, false);
qrcode_detector = new cv.wechat_qrcode_WeChatQRCode(
"detect.prototxt",
"detect.caffemodel",
"sr.prototxt",
"sr.caffemodel"
);
updateStatus("OpenCV Model Created");
}
}
```
这些文件为wechat_qrcode引擎的 CNN modelsDetector model 和 Super scale model。将模型文件加载成功后转换为 `Uint8Array` 加载到引擎中,然后调用`new cv.wechat_qrcode_WeChatQRCode( “detect.prototxt”, “detect.caffemodel”, “sr.prototxt”, “sr.caffemodel” )`实例化返回引擎实例。
官方model文件 [GitHub - WeChatCV/opencv_3rdparty: OpenCV - 3rdparty](https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode)
作为对比demo中添加了git上star比较多的jsqr库一同对照测试。
## 识别二维码
因为demo特定需求发票二维码基本在左上角所以在canvas加载图片时只截取左上角图片提高引擎识别效率。
<img width="562" alt="CleanShot 2022-05-23 at 17 24 28@2x" src="https://user-images.githubusercontent.com/11383747/169796294-993433c3-3e97-46a9-8651-8fd76152ca27.png">
OpenCV识别结果
![CleanShot 2022-05-23 at 17 26 12@2x](https://user-images.githubusercontent.com/11383747/169796337-7ba2a129-b357-41b8-a8a9-20484a9b30c8.png)
将二维码信息和二维码区域都正确的处理OpenCV耗时: 224.42822265625 ms。
而jsqr是处理不了这样的图片的。
**识别旋转的二维码**
![CleanShot 2022-05-23 at 17 28 48@2x](https://user-images.githubusercontent.com/11383747/169796380-f85584a5-b8a9-45ca-94ff-80dabc786225.png)
照片被旋转了90度且不太清晰同样也被正确的处理OpenCV耗时: 169.523193359375 ms。
jsqr也不能处理这样的图片。
**电子二维码识别:**
![CleanShot 2022-05-23 at 17 32 11@2x](https://user-images.githubusercontent.com/11383747/169796414-ae279015-dc5e-42f1-af7b-6b085a2b22f8.png)
电子版的发票图片都正确的识别了OpenCV耗时: 165.333984375 msQRjs耗时: 44.613037109375 ms。不过QRjs的效率相对会高一些。
## 浏览器兼容性:
暨WebAssembly兼容性基本上现代浏览器都是支持的
<img width="789" alt="CleanShot 2022-05-23 at 17 16 35@2x" src="https://user-images.githubusercontent.com/11383747/169796444-07af908a-48a6-448f-b458-56175ad2576d.png">
## 总结
OpenCV因为需要加入wechat_qrcode组件所以必须使用自定义编译。需要在本地搭建c++的编译环境是前端基本不曾涉足的领域相对较为繁琐也会有一些困难但这也让前端具备了更强大的本领由于WebAssembly的存在前端也有了更多的可能。
总之,由于前端越强大,我们能做的事也越多,挑战也会越大,大家共勉。
## 参考
[编译微信二维码引擎到webAssembly实践 | 虚幻](https://qwertyyb.github.io/2021/06/19/%E7%BC%96%E8%AF%91%E5%BE%AE%E4%BF%A1%E4%BA%8C%E7%BB%B4%E7%A0%81%E5%BC%95%E6%93%8E%E5%88%B0webAssembly%E5%AE%9E%E8%B7%B5/)
OpenCV: https://github.com/opencv/opencv
OpenCVs contrib: https://github.com/opencv/opencv_contrib