[译] 有了 TensorFlow.js,浏览器中也可以实时人体姿势估计

3,148 阅读8分钟
原文链接: blog.csdn.net

翻译文章,内容有删减。原文地址:medium.com/tensorflow/…

与谷歌创意实验室合作,我很高兴地宣布发布TensorFlow.js版本的PoseNet,这是一种机器学习模型,允许在浏览器中进行实时人体姿势估计。您可以访问storage.googleapis.com/tfjs-models… 尝试一下在线演示。

image

image

PoseNet可以使用单姿态或多姿态算法检测图像和视频中的人物形象 - 全部来自浏览器。

那么,问题来了,什么是姿态估计?姿态估计是指在图像和视频中检测人物的计算机视觉技术,以便人们可以确定某个人的肘部在图像中出现的位置。需要澄清的是,这项技术并不能识别谁在图像中 - 没有任何与识别身份相关的个人身份信息。该算法仅仅估计关键身体关节的位置。

好吧,为什么这是令人兴奋的开始? 姿态估计有很多用途,从对身体做出反应的交互式安装到增强现实、动画、健身用途等等。我们希望此模型的辅助能力能够激励更多的开发人员和制造商尝试将姿态检测应用到他们自己的项目中。虽然许多可选的姿态检测系统已经开源,但都需要专门的硬件和/或相机,以及相当多的系统设置。PoseNet运行在TensorFlow.js上,任何拥有摄像头的PC或手机的人都可以在网络浏览器中体验这种技术。 而且由于我们已经开源了这个模型,JavaScript开发人员可以用几行代码来使用这个技术。更重要的是,这实际上可以帮助保护用户隐私。由于TensorFlow.js上的PoseNet在浏览器中运行,因此任何姿态数据都不会留在用户的计算机上。


PoseNet入门

PoseNet可用于估计单个姿势或多个姿势,这意味着该算法的一个版本只能检测图像/视频中的一个人,而另一个版本可以检测图像/视频中的多个人。为什么会有两个版本?单人姿势检测器更快,更简单,但图像中只能有一个主体(稍后会深入探讨)。我们先探讨更容易使用的单个姿势。

在上层看来,姿势估计发生在两个阶段:

  1. 输入RGB图像到卷积神经网络。
  2. 使用单姿态或多姿态解码算法来解码姿势、构建置信度得分、关键点位置和来自模型输出的关键点置信度得分。

等等,这些关键词的含义是什么? 让我们回顾一下最重要的:

  • 姿势 - 在最上层看来,PoseNet将返回一个姿势对象,其中包含每个检测到的人物的关键点列表和实例层的置信度分数。

image

PoseNet返回检测到的每个人的置信度值以及检测到的每个姿势关键点。图片来源:“Microsoft Coco:上下文数据集中的通用对象”,cocodataset.org

  • 姿势置信度 - 这决定了对姿势估计的整体置信度。它介于0.0和1.0之间。它可以用来隐藏不够确定的姿势。
  • 关键点 - 估计的人体姿势的一部分,例如鼻子、右耳、左膝、右脚等。它包含位置和关键点置信度分数。PoseNet目前可检测到下图所示的17个关键点:

image

PosNet检测的17个姿势关键点。

  • 关键点置信度得分 - 这决定了估计关键点位置精度的置信度。它介于0.0和1.0之间。它可以用来隐藏不够确定的关键点。
  • 关键点位置 - 检测到的关键点在原始输入图像中的x和y二维坐标。

第1步:导入TensorFlow.js和PoseNet库

将模型的复杂性抽象化并将功能封装为易于使用的方法,这放面已经做了很多工作。让我们回顾一下如何配置PoseNet项目的基础知识。

该库可以通过npm安装:

npm install @tensorflow-models/posnet

使用es6模块导入:

import * as posenet from '@tensorflow-models/posenet';
const net = await posenet.load();

或通过页面的bundle:

<html>
  <body>
    <!-- Load TensorFlow.js -->
    <script src="https://unpkg.com/@tensorflow/tfjs"></script>
    <!-- Load Posenet -->
    <script src="https://unpkg.com/@tensorflow-models/posenet">
    </script>
    <script type="text/javascript">
      posenet.load().then(function(net) {
        // posenet model loaded
      });
    </script>
  </body>
</html>

第2a步:单人姿态估计

image

应用于图像的单人姿势估计算法示例。图片来源:“Microsoft Coco:上下文数据集中的通用对象”,cocodataset.org

如前面所说的,单姿态估计算法更简单、速度更快。它的理想场景是只有一个人在输入图像或视频的中间。缺点是,如果图像中有多个人,那么来自两个人的关键点可能会被估计为是同一个单一姿势的一部分 - 例如,#1的左臂和#2的右膝由该算法确定为属于相同姿势而可能被合并。如果输入图像可能包含多人,则应该使用多姿态估计算法。

我们来看看单姿态估计算法的输入:

  • 输入图像元素 - 包含要预测图像的html元素,例如video或img标签。重要的是,图像或视频元素应该是方形的。
  • 图像比例因子 - 0.2和1之间的数字。默认为0.50。在输入到网络之前的缩放图像比例。将此数字设置得较低可以缩小图像,以牺牲精度为代价加快速度。
  • 水平翻转 - 默认为false。如果姿势应该水平翻转/镜像。对于默认水平翻转(比如网络摄像头)的视频,这应该设置为true,这样返回的姿势方向才正确。
  • 输出步幅 - 必须为32、16或8。默认值为16。在内部,此参数会影响神经网络中图层的高度和宽度。在上层看来,它会影响姿态估计的精度速度。输出步幅值越低精度越高但速度越慢,数值越高速度越快,但精度越低。查看输出步幅对输出质量的影响的最好方法是尝试使用这个单姿态估计的示例: storage.googleapis.com/tfjs-models…

现在让我们看一下单姿态估计算法的输出

  • 包含姿势置信度得分和17个关键点数组的姿势。
  • 每个关键点都包含关键点位置和关键点置信度分数。同样,所有关键点位置在输入图像空间中都有x和y坐标,并且可以直接映射到图像上。

一下这个简短的代码块展示了如何使用单姿态估计算法:

const imageScaleFactor = 0.50;
const flipHorizontal = false;
const outputStride = 16;
const imageElement = document.getElementById('cat');
// load the posenet model
const net = await posenet.load();
const pose = await net.estimateSinglePose(imageElement, scaleFactor, flipHorizontal, outputStride);

一个输出姿势的例子如下所示:

{
  "score": 0.32371445304906,
  "keypoints": [
    { // nose
      "position": {
        "x": 301.42237830162,
        "y": 177.69162777066
      },
      "score": 0.99799561500549
    },
    { // left eye
      "position": {
        "x": 326.05302262306,
        "y": 122.9596464932
      },
      "score": 0.99766051769257
    },
    { // right eye
      "position": {
        "x": 258.72196650505,
        "y": 127.51624706388
      },
      "score": 0.99926537275314
    },
    ...
  ]
}

第2b步:多人姿态估计

image

一个应用于图像的多人姿态估计算法的示例。 图片来源:“Microsoft Coco:上下文数据集中的通用对象”,cocodataset.org

多人姿势估计算法可以估计图像中的许多姿势/人物。它比单姿态算法更复杂并且速度稍慢,但它的优点是,如果图片中出现多个人,他们检测到的关键点不太可能与错误的姿势相关联。出于这个原因,即使应用场景是检测单人姿势,该算法也可能更合乎需要。

此外,该算法的一个吸引人的特性是性能不受输入图像中人数的影响。无论是15人还是5人,计算时间都是一样的。

让我们看看输入

  • 输入图像元素 - 与单姿态估计相同
  • 图像比例因子 - 与单姿态估计相同
  • 水平翻转 - 与单姿态估计相同
  • 输出步幅 - 与单姿态估计相同
  • 最大姿势检测 - 整数,默认为5,要检测的姿态的最大数量。
  • 姿势可信度阈值 - 0.0至1.0,默认为0.5。在上层看来,这将控制返回姿势的最低置信度分数。
  • 非最大抑制(NMS)半径 - 以像素为单位的数字。在上层看来,这控制了返回姿势之间的最小距离。该值默认为20,这对大多数情况来说可能是正确的。它应该增加/减少,以滤除不太准确的姿势,但只有在调整姿势置信度分数不够好时使用。

查看这些参数有什么效果的最好方法是尝试使用这个多姿态估计的示例:storage.googleapis.com/tfjs-models…

让我们看一下输出

  • 一组姿势数组。
  • 每个姿势包含与单人估计算法中相同的信息。

下面这段简单的代码块展现了如何使用多姿态估计算法:

const imageScaleFactor = 0.50;
const flipHorizontal = false;
const outputStride = 16;
// get up to 5 poses
const maxPoseDetections = 5;
// minimum confidence of the root part of a pose
const scoreThreshold = 0.5;
// minimum distance in pixels between the root parts of poses
const nmsRadius = 20;
const imageElement = document.getElementById('cat');
// load posenet
const net = await posenet.load();
const poses = await net.estimateMultiplePoses(
  imageElement, imageScaleFactor, flipHorizontal, outputStride,    
  maxPoseDetections, scoreThreshold, nmsRadius);

姿势数组输出的样例如下所示:

// array of poses/persons
[ 
  { // pose #1
    "score": 0.42985695206067,
    "keypoints": [
      { // nose
        "position": {
          "x": 126.09371757507,
          "y": 97.861720561981
         },
        "score": 0.99710708856583
      },
      ... 
    ]
  },
  { // pose #2
    "score": 0.13461434583673,
    "keypositions": [
      { // nose
        "position": {
          "x": 116.58444058895,
          "y": 99.772533416748
        },
      "score": 0.9978438615799
      },
      ...
    ]
  },
  ... 
]

读到这儿,您就获得了足够的知识理解PoseNet示例。 如果您想了解更多关于该模型和实施的技术细节,请阅读原文:medium.com/tensorflow/… ,里面附录了更多的技术细节。

image