- 利用getUserMedia获取摄像头权限
- 将摄像头返回的媒体流扔到video标签
- 使用canvas抓取video的某一帧画面
- 将其canvas转为base64通过wechat-qrcode-ocr-wasm解析其中是否包含二维码(这步很慢)
- 当这步完成后才会执行video下一次画面帧抓取/或直接绘制二维码所在区域的图形,导致抓取的画面很慢,往往画布上的每秒帧数不会超过3帧,需要对着二维码区域停留很久才能抓到比较清晰的二维码照片
// 解析二维码 const video = this.$refs.video const canvas = this.$refs.canvas const ctx = canvas.getContext('2d') ctx.drawImage(video,0,0,canvas.width,canvas.height) const img = canvas.toDataURL() // 第一种 // 到这一步就很慢了,画布上的帧数可以说是PPT也不为过 // 因为必须等该接口返回才能抓下一帧 this.getCode(img).then(result=>{ conast {size,data,points} = result if(size === 0){ this.animationTimer = window.requestAnimationFrame(()=>{ //继续调用这个解析二维码函数 }) return } // 绘制扫码完成后的动画特效 }) // 第二种 // 这种很快就会RuntimeError: Aborted(). Build with -sASSERTIONS for more info // 在不停的抓取video图片,并发起解析的请求,就会开始加载图片 // 如果通过节流器控制应该会好点,但没试过 this.animationTimer = window.requestAnimationFrame(()=>{ //继续调用这个解析二维码函数 }) this.getCode(img).then(result=>{ conast {size,data,points} = result if(size === 0){ return } this.clearTimer(); // 绘制扫码完成后的动画特效 })
回答:
思路没啥问题,主要是对视频的解析。
如果是纯前端来做,建议在play
事件中做好节流,识别这块你用的wechat-qrcode-ocr-wasm
没听过,不过可以试一下jsqr
或zxing
.
另外建议用Web Worker
开子线程做解析。
要想更快更准确的解析出二维码,这里给几个思路和建议:
- 通过调整二维码插件参数
- 优化图片,比如提高图片对比度、减少图片的噪点
- 减小扫描的区域:可以减小图片的解析
- 调整视频流的分辨率,分辨率太高也会导致图片解析慢
- 提高CPU和GPU,这是硬件方面的了
如果有条件,建议第2、5两条在服务器上完成,甚至可以把视频流全给服务端,让服务端去生成。如果不行只能前端自己搞,关键就是优化,优化的好识别的就快、准。
另外给个减少噪点和增加对比度的代码吧,你根据自己的需求去调试:
// 获取图片元素 const img = document.getElementById('image'); // 创建Canvas元素 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 将图片绘制到Canvas中 canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); // 获取像素数据 const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; // 减少噪点 for (let i = 0; i < data.length; i += 4) { const gray = (data[i] + data[i + 1] + data[i + 2]) / 3; // 转换为灰度值 const threshold = 128; // 阈值 const value = gray < threshold ? 0 : 255; // 二值化 data[i] = data[i + 1] = data[i + 2] = value; } // 提高对比度 const contrast = 1.5; const intercept = -(0.5 * contrast) + 0.5; for (let i = 0; i < data.length; i += 4) { const value = data[i] * contrast + 255 * intercept; data[i] = data[i + 1] = data[i + 2] = value; } // 将处理后的像素数据绘制回Canvas中 ctx.putImageData(imageData, 0, 0); // 将Canvas转换为图片元素 const newImg = new Image(); newImg.src = canvas.toDataURL(); document.body.appendChild(newImg);
记得这种计算类的代码尽量不要在主线程跑,可能会阻塞甚至卡死。
希望能对你有帮助吧