适用于图像实时识别,形状识别,人脸识别等场景
相机组件
<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);
// 转成图片 base64
this.frameToBase64(frame).then((base64: string) => {
// 调用识别 API
this.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(); // ArrayBuffer
if (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 {
// 创建离屏 canvas
const 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);
// 将帧数据复制到 ImageData
const data = new Uint8Array(frame.data);
imageData.data.set(data);
// 将 ImageData 绘制到 canvas
ctx.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);
}
});
},