发布者:Dan Oved,谷歌创意实验室的自由创意技术员,纽约大学ITP的研究生。
编辑和插图:艾琳阿尔瓦拉多,创意技术师和亚历克西斯加洛,自由平面设计师,在谷歌创意实验室。
与Google CK S a i ) yreative Lab合作,我很高兴地宣布发布TensorFlow.js版本的PoseNet,一个允许在浏览器中进行实时人体姿势估计的机器学习模型。在这里试一试现F C l g t _ 5 3 v场演示。
PoseNet可以使用单一姿势或多姿势算法检测图像和视频中的人物-所有这些都可以在浏览器中进行
那么什么是姿势估计呢?姿势估计c y $ G是指计算机视觉技术,它可以检测图像和视频中的人物,以便确定,例如,某人的肘部在图像中出现的位置。更清楚的是,这项技术并没有识别出图像中的人R G Z b H },也没有与姿4 ( H @ z t r H势检测相关的个人识别信息。3 $ L o g ? & % 9算法只是简单地估计关键身体关节的位置。
好吧,为什么一开始就让人兴奋?姿势估计有很多用途,从对身体S 8 R g T H ` ;做出反应的交Y b & /互式 装置到增强现实、动画、健l X 4 T D +身用途等等。我们希望这个模型的可访问性能够激励更多的开发者和制作者在他们自己独特的项目中进行姿势检测的实验和应用。虽然许多替代姿态检测系统都是开源的,但所有这些系统都需要专门~ w # ) q的硬件和或摄像头,# ] o R G r y C +以及相当多的系统设置。随着PoseNet在TensorFlow.js上的运行,任L Y Z A & ? 8 t何拥有一个配备了不错的网络摄像头的桌面或手机的人都可以在网络浏览器中体验这项技术。由于我们已经开放了该模型的源代$ q 4 N z码,Javascript开发人员只需几行代码就可以修补t q 4并使用这项技术。此外,这实际上有助于保护用户隐私。由于TensorFlow.js上的PoseNet在浏览J n , 4 Q b器中运行,因此任何姿势数据都不会离开用户的计算机。
在我们深入研究如何使用这个模型之前,首先向所有使这个项目成为可能的人欢呼:George Papandreou和Tyler Zhu,谷歌的研究人员,他们是论文的幕后推动者致力于精Y 0 N & X确的野外多人姿势估计E h N 7 % b 3 `和PersonLab:基于自下而上部分的个人姿= m q G N A势估计和实例分割,几何嵌入模型,Nikhil Thorat和Daniel Smilkov,TensorFlow.js库背后的Google Brain团队的工程师。
PoV i wseNet入门
PoseNet可用于估计单个姿势或多个姿势,这意味着算法的一个版本只能检测图像/视频中的一个人,而另一个版本可以检测图像/视频中的多个人。为什么有两个版本?单人姿势检测器更快更简单,但只h v :需要图像中的一个对象(稍后会详细介绍)。我们先介绍一l v y 0 -下单体式,因为它更容| e G 8 L E易跟随。w { r j
在高层次上,姿态估~ = G计分为两个: A ,阶段:
- 通过[ W n L ^ 3 Y /卷积神经网络输入RGB图像
- 使用单姿2 P I态或多姿态解码算法对模型输出的姿f 8 % J 3 7 U } S态(Pose)、姿态置信度得分(Pose1 V { confidence score)、关键点位置d a O f m a(Keypoint Position)和关键点置信度得分(Keypoint Confidence Score)进行解码。
等等,这些关键词是什么意思?让我们回顾一下最重要的:
- 姿态(Pose) — 在最高级别,PoseNet将返回一个pos4 k j G 6 ce对象,该对象包含每个检测到的人的关键点列表和实例级置信度分数。 PoseNet为检测到的每个人以及检测到的每个姿势关键点返回置信值。图片来源:“Microsoft Coco:! { X :当前数据集中的公共对象”, https://cocodataset.org.
- 姿态置信度得分(Pose confidence score) — 这决( J 7 m 8 9 x定了姿态估计的总体置信度。范围在0.0到1.0之间。它可以用来隐藏被认为不够强壮的姿势。
- 关键点(Keypoint) — 估计的人的姿势的一部分,如鼻子、S - ] @ p 7 w右耳、左膝、右脚等。它包含一: n # T q个位置和一个关键点的信心得分。PoseNet目前检测到17个关键点,如下图所示:
PoseNet检测到1 7个姿势关键点
- 关键点置信度得分(Keypoint Confidence Score) — 这将确定估计的关键点位置是否准确的置信F b k | K度。范围在0.0到1.0之间。它可以用来隐藏被认为不够强大的关键点
- 关键点位置L k h ; o 9 7 {(Keypoint Position) — 检测到关键点的R ? # c m h C s原始输入图像中的二维x和3 Y W Fy坐标。
Part 1: 导入TensorFlow.js和PoseNet库
在抽象模型的复杂性和将功能封M B v m _ w V | &装Z & : # X R r = f为易于使用的方法方面做了大量工作。让我们回顾一下如L 3 f J [何设置PoseNet项目的基础知识。
可以使用npm安装库:
npH 8 G 4 W ) 8 +m install @tensorflow-models/posenet
并使用es6模块导入:
import * as posenet from \'@tensorflow-models/posenet\'; const net = await posenetc r X n.load();
或者通过页, p B W C $面中的捆绑:
<html>
<body>
<!-- Load TensorFlow.js -->
&l4 ) H p ! `t;scri/ w # o Ypt src=\"https://unpkg.com/@tensorflow/tfjs\"></script>
<!-- Load Posenet -->
<v i 4 1 o D 8 .;script src=\"https://b 0 Yunp& e Zkg.com/@tensorflow-models/posenet\">
</script>
<script type=\"text/javascript\">
posenet.load().t- ~ K _ 4 - 8hen(function(net) {
// posenet model loaded
});
</script>
</body>
</html>
Part 2a: 单人姿势估计
应用于图像的示例单人姿势估计算法。图片来源: https://cocodataset.org
如前所述,单姿态估计算法是两种算法中比较简单和快速的。它的理想用例是, u } j : #当一/ Q ~ I n个输# i C入图像或视频中只有一个人的时候。缺点是,如果一个图像中有多个人,两个人的关键点很可能被估计为同一个姿势的一部分,这意味着,例如,该算法可能将第一个人的左臂和第二个人的右膝合并为属于同一姿势。如果输入图像可能包含多人,0 z A则应使用多姿态估计算法。
让我们回顾一下单姿态估计算法的输入:
- 输入图像元素(Input image element) — 一个html元素,它包含一个要预测姿势的图像,例如视频或图像标记。重要的是,输入的图像或视频元素应该是方形的
- 图像比例因c e * _ C子(Image scale factor) — 介于0.2和1之间的数字。默认为0.50。在通过网络传G S u ^ r B ?送图像之前,通过什么来缩放图像。) V & r # 5将此数字设置得更低,以缩小图像并在通过网络传输时提高速度,但会降低精度
- 水平翻转(Flip horizontal) — 默Z M | g i h h认为false。如果姿势应该水平翻转/镜像。对于默认水平翻转视频(即网络摄像头)的视频,这应该设置为true,并且您希望以正确的方向返回姿势
- 输出跨距(Output stride) — 必须是32、16或8。默认为16。5 L H - k + _ & O在内部,该参数影响神经网络中层t h 8的高度和宽度。在较高的水平上,它会影响姿态估计的精度和速度。输出跨距的值越低精度_ 2 . S h W p D越高但速度越慢,值越高速度越快但精度越低。查看输出跨d 0 / 8 ? * }距对输出质量影响的最佳方法是使用单姿势估计演示
现在让我们回顾一下单姿态估计算法的输@ B }出:
- 一种[ 1 C r & p 姿势,包含一个姿势置信度得分和一个由17个关键点组成的数组。
- 每个关键点包含一个关键点位置和一个关键点信心得分。同样,所有的关键点位置在输入图像空间中都有x和y坐标,并且可以直接映射到图像上。
此短代码块显示了如何使用单姿态估计算法:
const imageScaleFactor = 0.50;
const flipE ] I I r Horizontal = false;
const outputStride = 16;
const imageElement = document.get& s L # 0 u fElementById(\'cat\');
// load the posenet model
const net = await posene- O dt.load();
const pose = await net.estimateSinglePose(imageElement, scaleFactor, flipHorizontal, ouu B F g s B [ gtputStride);
示例输出姿势如下所示:
{
9 - W O c ~ G q o\"score\": 0.32371k j l f 0 m @445304906,
\"keypointsO y x ] _ E a ) T\": [
{ // nose
\"position\": {
\"x\": 301.42237830162,
\"yw P ! 9 ? B q :\": 177.69162777066
},
\"score\": 0.99799561500549
},
{ // left eye
\"position\": {
d = b g\"xB ^ ) Z I Q I ] k\": 326.05302262306,
\"y\": 122.9596464932
},
\"score\": 0.99766051769257
},
{ // right eye
\"position\": {
\"x\": 258.72196650505,
\"y\": 127.51624706388
},
\"score\": 0.99926537275314
},
...
]
}
Part 2b: 多人姿态估计
应5 ? ) k 4 . q用于图像的多人姿态估计算法示例。图片来源:https://cocodataset.org
多人姿态估计算法可以估计图像中的多个姿态。它比单一姿势算法更复杂,y R U ` F {速度稍慢,但它的优点是,如果一K = ( {张图片中出现多个人,他们检测到的关键点就不太可能与错误的姿势相关联。因此,即使用例是为了检测一个人的姿势,这个算法可能更可取。
此外,该算法的一个吸引人的特性L C是性能不受输入图像中的人数的影响。无论是15人检测还是5人检测,计算时间都是一样的。
让我们回顾一h a ) W Z b X {下输入:
- 输入图像元素(Input image element) — 与单姿态估计相同
- 图像比例因子(Image scale fa~ - X ; s n X Bctor) — 与单姿态估计相同
- 水平翻转(Flip horizontal) — 与单姿态估B 6 { u计相同
- 输出跨距(Output stride) — 与单姿态估计相同
- 最大姿态检测(Maximum pose detections) — 一个整数。默认为5。要检测的pose的最大数目
- 姿势置信得分阈值(Pose confidence score threshold) — 0.0到1.0。默认为0.5。在高水平上,这可以控制返回pose的最小置信分Z l 3数
- 非最大抑D [ ! ?制(NMS) — 半径 以像素为单位的数字。在高级别上R N,这控制返回的姿势之间的最小距离。这个值默认为20,这在大多数情况下可能是好的。它应该增加/减少,作为一种过滤不太准确( ` t q的姿势的方法,但只有在调整姿势信心分数不够好的情况下。
要了解这些参数的效果,最好的方} | 7 E e法是使用多姿态估计演示。
让我们回顾一下 T [输出:
- 输出一系列姿势的Promi9 # S ; - O T Ise
- 每个姿势包含的信息与单人估计算法中描述的相同。
此短代K = 3 F S码块演示如何使用多姿态估计算法:
const imag- { 4eScaleFactor = 0.50;
c[ ] q l k V + Fonst flipHorizontal = false;
const outputStride = 16;
// get up toD I * i r W = & s 5 poses
const maxPoseDetections = 5;
// minimum confidence of the0 4 ~ root part of a pose
const scoreThreshold = 0.5;
// minimum distance in pix: r pels 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(
imageElemm { -ent, imageScaleFactor, flipHorizonta[ 4 m A Nl, outpuR F G d ~ g } 6tStride,
maxPoseDetections, scoreThreshold, nmsRadius);
姿势的示例输出数组如下所示:
// array of poses/persons
[
{ // pose #1
\"score\": 0.42985695206067,
\} , d ( !"keypoints\": [
{ // nose
\"position\": {
\"x\": 126.09371757507,
\"y\": 97.8614 / A B g V q l720561981
},
\"score\": 0.99710708856583
},
...
]
},
{ // pose #2
\"score\": 0.13461434583673,
\"keypositions\": [
{ // nose
\"position\":y F [ u S y E W {
\"x\": 116.58444P Y ) ]058895,
\"y\":j - ] ; c ] p 99.772533416748
},
\"score\": 0.99784386157i m & I 3 Q 199
},
...
]
},
...
]
如果你已经读了这么多,你知道的足够多了,可以开始使用PoseNet演示了。这可能是一个很好的停止点。如果您想了解更多关于模型和实现的k W A 技术细节,我们邀请您继续阅读下面的内容。
对于更好奇的人:技术的更深处
在这一节C _ Y ( ; / V中,我们将讨论关于单姿态估计算法1 7 } x Y的更多技术细节。在较高层次上,流程如下:
使用PoseN@ ) v M d _ Met的单人姿势- H K ) ~ 2 w检测器管道
需要注意的一个重要细节是,研究人员训练了PoseNet的ResNet和MobileNet模型。ResNet模型具有较高的精度,7 & z但由于其规模大、层次多,使得页面加载时间和推理时间都不适合任何实时应用。我们采用了MobileNet模型,因为它是为在移动设备上运行而设计的。
单姿态估计算法再探讨
处理模型输入:输出步幅(output strides)的解释
首先,我们将讨论如b P T何通过输出步幅获得PoseNet模型输出(主要是热图和偏移向量)。
方便5 B 0 S |的是,PoseNet模型是图像大小不变的,这意味着无论图像是否缩小,它x W j x + E都可以在与原始图像相同的尺度上预测姿态位置。这意味着PoseNe[ z z / a * 4 * _t可以通过在运行时设置上面提到的输出步幅来配置为以牺牲性能为代价具有更高的精度。
输出跨距决定了我们相对于输入图像大小n A 0 . R + J缩小输出的程度。它影响图层的Z 1 ^ +大小和模型输出。输出步长1 # r Z越大,网络层和输出层的分辨率就越小,相应的精度也就越低。在这个实现中,输出跨距的值可以是8、16或32。换句话说,32的输出步幅将导致最快的性能,但精度最低;8的输出步幅将导致最高的精度,但性能最低。我们建议从16开始。
输出步幅决定了我们5 { w s h相对于输入图像大小缩小输出的程度。输出步幅越大,速度越快,但精度越低
在引擎盖下面,当输出跨距设置为8或16时,层中的输入跨距量减少,以创建更大的输出分辨率。然后使用, w 5 O c - o阿托鲁斯卷积使随后层中的卷积滤波器具有更宽的视野(当输出跨距为32时不应用阿托鲁斯卷积)。虽然Tensorflow支持atrus卷积,但Tensorflow.js不支持,因此我们添加了一个PR来包含这个。
模型输出:热图和偏移矢量
当PoseNet2 A 8 ]处理一个图像时,实际上返回的是/ u G J一个热图和偏移向量,这些向量可以被解码以在图像中找到与姿势关键点相对应的高置信度区域。我们将在一分钟内讨论每一个关键点的含义,但M p t N f现在下面的插图从高层捕捉到每个姿势关键点是如何与一个热图张量和一个偏移向量张量相关联的。
PoseNet返回的17个姿势关键点中每一个都与一个热图张量n n _ f和一个用于确定关键- H W w 6 }点精确位置的偏移5 ~ } Z向量张量相关联
两个输出都是具有高度和宽度的三维张量,我们将其称为分辨率。根据以下公式,分辨率由输 入图像大小和输出步幅确定:
Resolution = ((InputImageSize - 1) / OutputStride) + 1
// Example: an input imag6 P C Z I d l 8e with a widtj d d s 4 *h of 225 pixels and an output
// stride of 16 results in an output resolution of 15
// 15 = ((225 - 1) / 16) + 1
热图
由于17是PoseNet检测到的关键点数量,因此每个热图都是一个大小分辨率x分辨率x 17的3D张量。例如,如果图像大小为225,输出跨距为16,则为15x15x17。三维(共17个)中的每个` 5 D切片1 5 # Z } # ( v M对应于特定关键点的热图。热图中的每个位置都有一个置O ; & e l信分数,这是该关键点类型的一部分存5 ? k I x K 3在于该位置的概率。它可以Q m ! d被认为是原始图像被分解成一个15x1c w 9 k @ 85的网格,其中热图分数提供了每个网格正方形中每个关键点存Q P [ P m l在的可能性的分类。
偏移矢量
每个偏移向量是尺k A V & a寸分辨率x分辨率x 34的3D张量,其中34是关键点的数目*2。图像大小为225,输出跨距为16,这将是15x15x34。由于热图是关键点所在位置的近似值p . W,因此偏移向量对应于热图点的位置,并0 l 5通过从对应的热图点沿向量移动来预测关键点的准确位置。偏移向量的前17个切片包含向量的x,后17个切片包含向量的y。偏移向量大小与原始图像的比例相同。
根据b ^ M模型输出估计姿态# d t & _
在图像通过模型后,我们进行一些计算来g ] T y ^ T $估计输出的+ Y L 3 4 _ M P姿态。例如,单姿态估计算法返回一个姿态置信度得分,它本身包含一个关键点数组(由部件ID索引),每个关Q . ^ ;键点都有一个置信度得分和x,y位置。要获取姿势O m =的关键点:
- 在热图上使用sigmoid激活函数以获得分数。 scores = heatmap.sigmoid()
- argmax2d对关键点信心得分(keypoint confidence scores)进行处理,以获得热图中的x和y指数,每个部分的得分最高,这实际上是该部分最有可能存在的地方。这将产生17x2大小的张量,其中每一行是热图中的y和x索引,每个部分的得分最高。 heatmapPositions = scores.argmaxm : K u : E $ O(yM z ; v d 9, x)
- 通过从对应于该零件的热图中的xr + ( J和y索引的偏移中获取x和y来检索每个零件的偏移向量。这会产生17x2大小的张量,每一行是对应关键点的偏移向量。例如,对于索引k处的零件,当热图位置为y和# n 0 n I M id时,偏移矢量为: offsetVector = [offset= 8 y Js.get(y, x, k), offsets.get(y, xL T H { =, 17 + k)]
- 为了得到关键点,将每个零件的热图x和y乘以输出跨距,然后将其添加到相应的偏移向量中,该偏移向量的比例与原始图像相同。 keypointPositions = heatmapPositions \\* outputStride + of& ? n & g ZfsetVectors
- 最后,每个关键点的置信度得分是其热图位$ i b 置的置信度得分。姿势自信得分是关键点得分的平均值。
多人姿态估计
多姿态X I X U : ! t估计算法的细节不在本文的讨论范围之内。该算法的主要区别在于,它使用贪心过程,通过沿着基于零件的图形跟踪位移向量,将关键点分组为姿势。具体来说,F t l j ? - E o它使用了研究论文中的快速贪婪解码算法PersonLab:自下而上、基于部分的几何嵌入模型的人体姿势估计和实例分~ S 0 c O Q ` 9割.
有关多姿态算法的更多信息,请阅读完整的研究论文或查看代码。我们希望随着更多的模型移植到TensorFlow.js,机器学习的世{ $ 3界对新的程序员和制作者来说变得更容易访问、更受欢迎、更有趣。在TensorFlow.js上的PoseNet只是一个小小的尝试。我们很想看看你做了什么 — 别忘了用#tensorflowjs和#posenet分享你的精彩项目!