TensorFlowJS遇到小程序

安装过程

  • 小程序官网 –> 登录 –> 设置 –> 插件 –> 添加插件
  • npm init –> install @tensorflow/tfjs-converter 和 @tensorflow/tfjs-core 以及 fetch-wechat
  • 小程序开发工具 –> 工具 –> 构建npm
  • 按照官网开发文档在app.json中进行声明 以及 在app.js的onLaunch中调用插件

创建camera对象和canvas对象

通过camera对象获取实时的姿势动作,传给后台模型去处理,处理结果通过canvas对象进行显示。

  • 创建camera对象

  • <camera>...</camera>中添加canvas对象

    使用TF模型

  • 打开TF官网

    • Body 用来实现人物与背景分离
    • Text toxicity 用来过滤掉敏感词汇
    • Universal sentence encoder 用来将文本进行编码为向量 可以通过向量来比较两个句子之间的相关性 做文本分类的工作
    • Object detection 用来检测一张图片上的多个物体 将物体进行分析出位置以及相关信息等
  • 使用PoseNet模型

    • 通过官网进入github页面 按照开发文档步骤 先安装包

      1
      yarn add @tensorflow-models/posenet引入
      1
      const posenet = require('@tensorflow-models/posenet')
      1
      2
      3
      4
      5
      6
      this.net = await posenet.load({
      architecture: 'MobileNetV1',
      outputStride: 16,
      inputResolution: 193,
      multiplier: 0.5
      })
  • 由于模型比较大,所以一般采取异步的方式去加载

    注意: 与前端开发不同

    前端开发需要什么包,就直接下载完成包;小程序中要考虑项目大小的问题,安装的都是子包

    要实现异步,需要安装npm install regenerator-runtime

    使用regenerator需要注意,在小程序开发工具 详情中 去掉ES6->ES5的转化

  • 异步加载模型 并 处理imgData

    域名问题 需要 到小程序官网的开发配置中 配置服务器信息 / 或者在开发工具的详情中 勾选不进行域名校验

    编写检测姿势函数detectPose(),图像数据是3通道数据,而模型接收到的只能是4通道数据,所以需要进行数据转化。

  • 使用tidy和estimatePose,注意内存的节约

  • 绘制姿态

    • 线
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    // index.js
    const tf = require('@tensorflow/tfjs-core')
    const posenet = require('@tensorflow-models/posenet')
    const regeneratorRuntime = require('regenerator-runtime')
    Page({
    // 因为模型加载时间会比较大 onLoad是在小程序打开加载时触发 将onLoad改为onReady 加载完成后触发
    async onReady() {
    const camera = wx.createCameraContext(this)
    // 后面需要将canvas去传给别的方法进行调用 所以将canvas作为this下的一个实例属性
    this.canvas = wx.createCanvasContext('pose', this)
    // 加载模型
    this.loadPosenet()
    // 计数器每隔4帧 显示信息
    let count = 0
    const listener = camera.onCameraFrame((frame) => {
    count++
    if (count === 4){
    if (this.net) {
    console.log(frame.data)
    this.drawPose(frame)
    }
    count = 0
    }
    })
    // listener.start()
    },
    async loadPosenet() {
    this.net = await posenet.load({
    architecture: 'MobileNetV1',
    outputStride: 16,
    inputResolution: 193,
    multiplier: 0.5
    })
    console.log('模型数据:',this.net);
    },
    // 检测的函数
    async detectPose(frame, net) {
    // 数据转化
    const imgData = {data: new Uint8Array(frame.data), width: frame.width, height: frame.height}
    const imgSlice = tf.tidy(() => {
    const imgTensor = tf.browser.fromPixels(imgData, 4)
    return imgTensor.slice([0, 0, 0], [-1, -1, 3]) // 第一个参数图片的[宽,高,通道数]
    })
    const pose = await net.estimateSinglePose(imgSlice, {flipHorizontal: false})
    imgSlice.dispose()
    return pose
    }

    // 画出来
    async drawPose(frame) {
    const pose = await this.detectPose(frame, this.net)
    if (pose == null || page.canvas == null) return
    if (pose.score >= 0.3) {
    for (i in pose.keypoints) {
    console.log(pose.keypoints[i]) //画点 下一步就是画线
    const point = pose.keypoints[i]
    if (point.score >= 0.5) {
    const {y, x} = point.position
    // Draw circle
    this.drawCircle(this.canvas, x, y)
    }
    }
    // Draw lines
    const adjacentKeyPoints = posenet.getAdjacentKeyPoints(pose.keypoints, 0.5)
    for (i in adjacentKeyPoints) {
    const points = adjacentKeyPoints[i]
    this.drawLine(points[0])
    }
    this.canvas.draw()
    },
    drawCircle(canvas, x, y) {
    canvas.beginPath()
    canvas.arc(x * 0.72, y * 0.72, 3, 0, 2 * Math.PI)
    canvas.fillStyle = 'aqua'
    canvas.fill()
    },
    drawLine(canvas, pos0, pos1) {
    canvas.beginPath()
    canvas.moveTo(pos0.x * 0.72, pos0.y * 0.72)
    canvas.LineTo(pos1.x * 0.72, pos1.y * 0.72)
    canvas.lineWidth = 2
    canvas.strokeStyle = 'aqua'
    canvas.stroke()
    }
    }
    })

版本问题太多了 重新自己跟着开发文档进行

  • 安装包

    1
    2
    3
    yarn add @tensorflow-models/pose-detection
    yarn add @tensorflow/tfjs-core, @tensorflow/tfjs-converter
    yarn add @tensorflow/tfjs-backend-webgl
  • 引入

    1
    2
    3
    4
    import * as poseDetection from '@tensorflow-models/pose-detection';
    import * as tf from '@tensorflow/tfjs-core';
    // Register one of the TF.js backends.
    import '@tensorflow/tfjs-backend-webgl';
  • 参考项目

    • 物体识别 mobilenet
    • 姿态识别 posenet
  • 完成项目