基于 OpenCV.js 的 Web 二维码扫描实现

730 阅读4分钟

扫码体验地址

image.png

我们常见的 扫码功能,一般常见于App 中 例如:微信, 支付宝。

Native App 扫码 有着丰富的组件生态 常用的码组件 ZXing 等。 是一个比较成熟的技术被广泛使用

混合开发的模式 :JSBridge 实现 web 调用 App 扫码 。本质还是调用 Native 扫码

image.png

一、web扫码

image.png

1.1 MediaDevices API

Navigator.mediaDevices 属性返回一个MediaDevices对象,MediaDevices 界面提供对连接的媒体输入设备(如相机和麦克风)以及屏幕共享的访问。从本质上讲,它可以让您访问媒体数据的任何硬件源。 该对象提供对连接的媒体输入设备(如相机和麦克风)以及屏幕共享的访问。该对象提供了5个api: enumerateDevices()、getDisplayMedia()、getSupportedConstraints()、getUserMedia()、selectAudioOutput()

image.png

getUserMedia(options) 方法询问用户是否允许使用媒体输入,即调用录制视频或者录音等功能,该媒体输入会产生包含所请求媒体类型的轨道,包括视频轨道(由硬件或虚拟视频源产生,例如相机、视频录制设备、屏幕共享服务等)、音频轨道(类似地,由物理或虚拟音频源,如麦克风、A/D 转换器等),可能还有其他音轨类型。 参数options:getUserMedia({ video:true, audio:false })

enumerateDevices() 列举可用的媒体输入和输出设备,例如麦克风、相机、耳机等。返回结果可用设备信息的数组;

getSupportedConstraints() 方法返回用户代理(即浏览器)支持的约束列表,数据格式为对象字典,键为约束的属性,值都为true(因为返回的都是支持的约束,所有都为true)。查看约束如何工作的更多信息

getDisplayMedia(opitons) 调用后会提示用户选择并授予权限,以将显示内容或其一部分(例如窗口)捕获为MediaStream(媒体内容流),即共享屏幕内容; 参数options举例:getDisplayMedia({ video:true, audio:false })

constraints 作为一个MediaStreamConstraints 对象,指定了请求的媒体类型和相对应的参数。 constraints 参数是一个包含了video 和 audio两个成员的MediaStreamConstraints 对象,用于说明请求的媒体类型. 扫码中只需要视频流 可将 audio 设置为false, 如何 根据手机分辨率 设置 video 视频分辨率从而影响我们截图的清晰度

image.png

constraints 约束 指定使用后置摄像头 1 video facingMode 使用 前置还是 后置摄像头 通过这种方式 在多个后置摄像头设备下的情况下 无法选择最清晰的摄像头 。 2 也可以通过指定 deviceId ,下文会讲到 如何选择获取 deviceId 。

image.png

image.png

navigator.mediaDevices.enumerateDevices 通过调用获得的设备列表navigator.mediaDevices.enumerateDevices()是一个对象数组MediaDeviceInfo, 每个媒体设备一个。

每一个设备信息包含 以下信息 deviceId ,groupId,kind, label

deviceId : 设备ID groupId: 如果两个设备属于同一物理设备,则它们具有相同的组标识符;例如,带有内置摄像头和麦克风的显示器。 kind: kind的只读属性MediaDeviceInfo返回一个枚举值,即“videoinput”、“audioinput”或“audiooutput” label:描述媒体设备的字符串。

出于安全原因, 如果用户未通过从麦克风或摄像头启动流或通过授予持久权限来获得使用至少一个媒体设备的权限,则始终为空字符串 label。""

通过 kind 属性值为videoinput 过滤获取所有的摄像头(前置+后置)

image.png

2 通过 label 属性值过滤所有后置摄像头 ,由于市场机型众多 没有同一的标准,判断 label 中是否包含以下 规则进行区分 , 例如 判断 通过 判断 label 中判断是否包含 back, rear等 。进行区分前置和后置摄像头

1.1 技术选型

在 Web 端二维码扫描场景中,主流方案包括:

  • ZXing (纯 JS 实现)

  • jsQR (轻量级解决方案)

  • OpenCV + WeChatQRCode (高性能方案)

1. 主流方案对比

方案优势 劣势适用场景 
jsQR轻量级,无需额外依赖识别率低,性能一般简单场景
ZXing功能全面,支持多种码制 包体积大,性能一般多码制需求
OpenCV + WeChatQRCode 识别率高,性能好 初始加载较慢,依赖较多复杂场景 

2. 为什么选择 OpenCV + WeChatQRCode?

  • 识别能力强

  • 支持复杂场景识别

  • 支持多个二维码同时识别

  • 支持倾斜、模糊等异常情况

2. 性能表现好

  • C++ 核心代码编译为 WebAssembly

  • 视频流处理性能优异

  • 内存占用可控