微信小程序camera相机帧转图片base64
适用于图像实时识别,形状识别,人脸识别等场景
相机组件
<camera class="camera-view" device-position="back" flash="off" binderror="onCameraError" bindinitdone="onCameraInit" frame-size="small"><!-- 扫描框 --><view class="scan-frame"></view></camera>
初始化相机
onCameraInit() {console.log('相机初始化完成');// 创建相机上下文this.cameraContext = wx.createCameraContext();// 获取系统信息判断平台const systemInfo = wx.getSystemInfoSync();const isIOS = systemInfo.platform === 'ios';let lastTime = 0;const interval = 3000; // 每3秒取一帧try {this.frameListener = this.cameraContext.onCameraFrame((frame) => {const now = Date.now();if (now - lastTime < interval) return; // 跳过多余帧lastTime = now;if (!frame || !frame.data || frame.data.byteLength === 0) {console.warn('帧数据为空或无效');return;}console.log('取到一帧', frame.width, frame.height, frame.data.byteLength);// 转成图片 base64this.frameToBase64(frame).then((base64: string) => {// 调用识别 APIthis.recognizeFrameData(base64, frame.width, frame.height);}).catch((error: any) => {console.error('frameToBase64 转换失败:', error);});});// iOS 使用 worker,Android 不使用if (isIOS) {try {this.worker = wx.createWorker('workers/cameraWorker.js', {useExperimentalWorker: true});this.frameListener.start({ worker: this.worker });} catch (error) {console.error('创建 Worker 失败,使用普通模式:', error);this.frameListener.start();}} else {this.frameListener.start();}console.log('相机帧监听器已启动');} catch (error) {console.error('启动相机帧监听失败:', error);}},
注意ios要使用workers
相关代码
// workers/cameraWorker.js
setInterval(() => {try {const frameData = worker.getCameraFrameData(); // ArrayBufferif (frameData.byteLength === 0) return;// base64 转换const base64 = wx.arrayBufferToBase64(frameData);console.log('iOS 帧 base64 长度', base64.length);// 可以 postMessage 给主线程做处理worker.postMessage({ base64 });} catch (err) {console.error(err);}
}, 1000); // 每秒处理一帧
这里直接获取的帧需要转换成图片base64,为什么要转?
小程序相机每一帧给的是 原始 RGBA 像素数据,并不能直接使用,而是需要转换。
目前的方案是创建一个canvas将图片像素图绘制上去,然后再把 canvas 内容 转成 Base64 格式的 JPEG。
frameToBase64(frame: any): Promise<string> {return new Promise((resolve, reject) => {try {// 创建离屏 canvasconst canvas = wx.createOffscreenCanvas({ type: '2d',width: frame.width, height: frame.height });const ctx = canvas.getContext('2d');if (!ctx) {reject(new Error('Failed to get canvas context'));return;}// 创建 ImageData 对象const imageData = ctx.createImageData(frame.width, frame.height);// 将帧数据复制到 ImageDataconst data = new Uint8Array(frame.data);imageData.data.set(data);// 将 ImageData 绘制到 canvasctx.putImageData(imageData, 0, 0);// 转为 base64 - 使用同步方式try {const base64 = canvas.toDataURL({type: 'image/jpeg',quality: 0.8});resolve(base64);} catch (e) {reject(e);}} catch (error) {reject(error);}});},
