微信小程序如何实现实现监听相机帧并按需回显于屏幕—wx.createCameraContext()和wx.createCanvasContext()或许可以实现

笔者为大二在读学生,最近做一个小程序植物识别的项目需要实现以下功能,苦苦寻找多方资料未果,故分享在探索路上获得的经验,以作抛砖引玉之用

  1. 进入页面监听自动相机帧数据
  2. 点击按钮推送相机帧数据到小程序AI进行推理
  3. 将推送的相机帧数据以小框显示在屏幕左中部

进入页面监听自动相机帧数据

这是笔者遇到的第一个坑,查询资料可知需先使用小程序的相机组件

html 复制代码
  <camera class="camera" 
  style="  width: 100vw; height: 80vh;" 
  device-position="back" 
  flash="off" 
  frame-size="medium">
  </camera>
js 复制代码
 onReady() {
     const context = wx.createCameraContext(this);
     const listener = context.onCameraFrame(frame => {
        // console.log('持续监听中')
           this.executeClassify(frame);
    });
    this.listener = listener
    
    //开始监听 经测试安卓无法正常监听,ios正常
    this.listener.start
 }

如果和以上代码一样在onReady生命周期里面触发监听,在预览中,我手上两台安卓手机均只能监听前几帧,小程序退到后台再进入又会刷新监听多几帧,ios正常,原因未知

解决办法

bindinitdone属性是可以使得对应方法在相机初始化完成时触发,将开始监听的方法绑定在该属性上可以实现进入页面自动开始监听相机帧

html 复制代码
<camera class="camera" 
   bindinitdone = "startListener"
  style="  width: 100vw; height: 80vh;" 
  device-position="back" 
  flash="off" 
  frame-size="medium">
  </camera>
js 复制代码
startListener(){
    this.listener.start({
      success: ()=> {
        console.log('开始监听成功');
        // 在成功回调函数中执行需要的操作
        wx.showToast({
          title: '开始识别',
          icon: 'loading',
          duration: 1000
        })
        this.setData({
          isStart: true
        })
      },
      fail: ()=> {
        console.log('开始监听失败');
        // 在失败回调函数中执行需要的操作
        wx.showToast({
          title: '请重试',
          icon: 'error',
          duration: 1000
        })
      },
    });
  },

点击按钮推送相机帧数据到小程序AI进行推理

这部分可以参考小程序AI推理的文档 developers.weixin.qq.com/miniprogram...

笔者在其基础上加了一个isClick的判定来实现点击后再推送相机帧数据

js 复制代码
    //原版 前一帧推理成功后自动推理下一帧
    const context = wx.createCameraContext(this); 
     
    const listener = context.onCameraFrame(frame => {

        if (this.classifier && this.classifier.isReady() && !this.predicting) {
           this.executeClassify(frame);
        }
    });
js 复制代码
    //修改后 推理成功且点击按钮后isClick为true才推理下一帧
    const context = wx.createCameraContext(this); 
     
    const listener = context.onCameraFrame(frame => {

        if (this.classifier && this.classifier.isReady() && !this.predicting && this.data.isClick) {
           this.executeClassify(frame);
        }
    });

将推送的相机帧数据以小框显示在屏幕左中部

关于Camera实时帧数据,小程序AI推理文档里面是这样解释的

OnCameraFrame 返回的 frame 包含属性 width、height 和 data,分别表示二维图像数据的宽度,高度,以及图像像素点数据。其中 data 为一个 ArrayBuffer,存储数据类型为 Uint8,存储的数据 format 为 rgba,即每连续的4个值表示一个像素点的 rgba。 详细关于 onCameraFrame 的内容可以参考CameraContext.onCameraFrame.

在Camera组件文档中也有类似的描述developers.weixin.qq.com/miniprogram...

要想将该格式的图像文件渲染到屏幕上,有多种选择,一是使用upng.js进行解码(据说平均耗时6-7s故并未使用),二是使用Canvas绘制,笔者使用的是后者

而小程序的Canvas也有新版和旧版,但是笔者使用新版Canvas时出现该报错,重复排查多次仍未解决,故使用小程序旧版Canvas

MiniProgramError Cannot read properties of null (reading 'node') TypeError: Cannot read properties of null (reading 'node')

html 复制代码
<camera class="camera" bindinitdone = "startListener" style="  width: 100vw; height: 80vh;" device-position="back" flash="off" frame-size="medium">
    <view class="res-container" wx:if="{{ isResultShow }}">
      <canvas class="res-image" canvas-id="ssd1" ></canvas>
    <view class="res-text"> 分类结果: {{predClass}}</view>
    <view bindtap="close" class="Icn">x</view>  
  </view>
  </camera>

其中需要注意的是Camera实时相机帧数据类型是ArrayBuffer ,如果使用 wx.canvasPutImageData() 绘制在Canvas画布上需要手动将监听的相机帧的Arraybuffer 数据转为uint8

js 复制代码
 onReady() {
     //获取Canvas绘图上下文
    this.ctx = wx.createCanvasContext('ssd1');
    const context = wx.createCameraContext(this);
    this.initClassifier();

    const listener = context.onCameraFrame(frame => {
        // console.log('持续监听中')
        // const fps = this.fpsHelper.getAverageFps();
        // console.log(`fps=${fps}`);

        if (this.classifier && this.classifier.isReady() && !this.predicting && this.data.isClick) {
           this.executeClassify(frame);
           //将监听的相机帧的arraybuffer数据转为uint8
           const data = new Uint8ClampedArray(frame.data); 

           wx.canvasPutImageData({
            canvasId: 'ssd1',
            x: 0, 
            y: 0,
            width: frame.width,
            height: frame.height,
            data: data,
            success (res) {
              console.log('canvas绘制成功', res)
                // after put image data
            },
            fail(error){
              console.log('canvas绘制失败',error)
            },
            complete(res){
              console.log('canvas绘制流程走完了',res)
            }
        })
        }
    });
    this.listener = listener
  },

至此,便实现标题所述基本功能,但仍存在不足

  1. 第一次点击按钮绘制Camera实时帧数据到Cavas画布时,绘制无内容且控制台报错

canvas绘制失败 {"errMsg": "canvasPutImageData:fail fail canvas is empty"}

不知道是不是wx:if控制显隐导致的,回去试一试 2. Canvas绘制的相机帧数据仅为原图左上角部分,设想是将Camera实时帧数据整体缩放为画布大小绘制,如何解决未知..

欢迎有经验的大佬在评论区畅言,希望有更优方案的出现

谨听教诲

相关推荐
赵庆明老师20 分钟前
Uniapp微信小程序开发:微信小程序支付功能后台代码
微信小程序·小程序·uni-app
FliPPeDround6 小时前
告别 uni-app 启动烦恼:@uni-helper/unh 让开发流程更顺畅
前端·微信小程序·uni-app
@二十六9 小时前
微信小程序订阅消息工具封装,兼容一次性订阅和长期订阅
微信小程序·小程序·订阅消息
用力的活着10 小时前
uniapp 微信小程序蓝牙接收中文乱码
微信小程序·小程序·uni-app
知识分享小能手11 小时前
微信小程序入门学习教程,从入门到精通,电影之家小程序项目知识点详解 (17)
前端·javascript·学习·微信小程序·小程序·前端框架·vue
笨笨狗吞噬者1 天前
【uniapp】体验优化:开源工具集 uni-toolkit 发布
性能优化·微信小程序·uni-app
知识分享小能手1 天前
微信小程序入门学习教程,从入门到精通,自定义组件与第三方 UI 组件库(以 Vant Weapp 为例) (16)
前端·学习·ui·微信小程序·小程序·vue·编程
爱隐身的官人1 天前
微信小程序反编译教程
微信小程序·小程序·小程序反编译
计算机徐师兄1 天前
Java基于SpringBoot的智慧校园管理系统小程序【附源码、文档说明】
java·微信小程序·小程序·智慧校园管理系统小程序·java智慧校园管理系统小程序·智慧校园管理系统微信小程序·智慧校园管理微信小程序
毕设源码-赖学姐1 天前
【开题答辩全过程】以 宝贝回家网微信小程序为例,包含答辩的问题和答案
微信小程序·小程序