H5摄像头扫描多个二维码,怎么解决帧数抓取慢的问题?
利用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();
// 绘制扫码完成后的动画特效
})
回复
1个回答
test
2024-07-07
思路没啥问题,主要是对视频的解析。如果是纯前端来做,建议在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);
记得这种计算类的代码尽量不要在主线程跑,可能会阻塞甚至卡死。希望能对你有帮助吧
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容