引入

项目需求:在前端使用camera组件持续扫描,将捕捉到的帧上传到后端进行算法识别判断,并返回判断结果。若结果为“成功”,则将捕捉到的正确帧显示在屏幕上。

尝试

wx.onCameraFrame(frame=>{
    //frame.width
    //frame.height
    //frame.data
})

wx.onCameraFrameAPI接受一个回调函数,返回frame的宽高和frame的图像编码(ArrayBuffer格式)

尝试(一)

经过查找,wx.arrayBufferToBase64API,可以实现arraybuffer到Base64的转换,但实际使用的过程中发现处理速度极其缓慢,并且对手机性能消耗太大,不满足实时性的需求

尝试(二)

网上查阅到jpeg-js可以实现ArrayBuffer到jpeg图片的转换。很开心地以为这个需求已经解决了。引入后发现报错,查看源码发现里边使用到了Buffer函数,在小程序的JS环境中并没有注入Buffer,所以无法使用这个库。

尝试(三)

后来发现了将arrayBuffer画到canvas上,再将canvas画布的图片导出为base64的方式,遂进行了尝试。

  • wx.canvasPutImageData
  • wx.canvasToTempFilePath
  • wx.getFileSystemManager()

    采坑1

    frame.data的格式为ArrayBuffer,不能直接上传,需要进行如下处理:

    var data = new Uint8Array(frame.data);
    var clamped = new Uint8ClampedArray(data);
    
    
     wx.canvasPutImageData({
            canvasId: 'getImg',
            x: 0,
            y: 0,
            width: frame.width,
            height: frame.height,
            data: clamped,
            success(res) { ... },
            fail(err) { ... }
    }

    采坑2

    fail canvas is empty

  • 问题:
    canvasPutImageData未绑定this
  • 解决方法:
    在函数开头定义变量that指向this,并使用that绑定

    //html
    <canvas canvas-id="myCanvas"></canvas>
    
    //js
    onReady(){
        const that = this
        wx.canvasPutImageData({ 
            canvasId: 'myCanvas'
            ...
        },that)
    }

    采坑3

    wx.canvasToTempFilePath报错:"create bitmap failed"
    在csdn中得到了解答:https://blog.csdn.net/txyzqc/...

  • 解决方法:
    用来存放图片的canvas不能设置 hidden="true",所以可以利用position: absolute进行绝对定位,使得canvas脱离文档流,并通过设置top和left等位置,将canvas移出视口。 此时,"create bitmap failed"错误不再发生。

性能瓶颈

在使用canvas方案后,基本功能实现了。但实际测试功能的过程中发现,对于系统版本较低的手机,卡顿情况依然有不小的影响。
经过反复查阅研究,发现canvas对于大数据量、高频率的处理性能确实是很差的。咨询小程序中心的开发人员得知:camera组件在gpu运行;oncameraframe在cpu处理arraybuffer;而拿到的cpu又通过canvas的API利用GPU获取图片数据,这样本身也是非常低效的。
眼见这种方法效果不佳,我们选择了另一条路。

图片上传

由于生成图片是个耗费性能的工作,所以理应使得传到后台的图片尽可能小,防止页面卡顿。但同时又需要将正确帧显示在页面上,这就造成了矛盾。

  • 错误尝试:每次上传帧的同时进行拍照,若拍照返回的结果是正确的,则将拍照的本地图片进行展示。
    问题:1.拍照的声音在ios端无法关闭;2.拍照消耗性能;3. 由于返回正确结果需要时间(http请求),而在这段时间里camera组件展示的帧页面已经发生了改变,所以在做照片展示时会感受到突兀的回跳。
  • 解决方式:在返回正确答案的瞬间进行拍照,这样性能的消耗较小,并且camera组件的帧画面是连续的。

最终解决方案:小程序部署TensorFlowJS

文档:https://github.com/GeekYmm/te...
最终效果:解决了卡顿问题,页面流畅体验良好。

后话

哪怕是选用了tfjs,最终还是存在问题的:内存泄漏。
在小程序开发者平台上面,抱怨camera组价内存泄漏的人非常多,并且很早就开始提议微信小程序进行改良了,但是至今为止还是存在这个问题。当长时间使用camera组件并从oncameraframe中取数据进行处理时,小程序就会越来越卡顿,直到最终客户端崩溃。目前还没发现很好的解法,可能这也是支付宝小程序一直不开放camera组件的原因吧。


Oliver
76 声望13 粉丝

Slow Done, Achieve More.