[譯] 在瀏覽器裏使用 TenserFlow.js 實時估計人體姿態

發佈者:Dan Oved,谷歌創意實驗室自由創意技術專家,紐約大學 ITP 研究生。 編輯和插圖:創意技術專家 Irene Alvarado 和谷歌創意實驗室自由平面設計師 Alexis Gallojavascript

在與谷歌創意實驗室的合做中,我很高興地宣佈 TensorFlow.jsPoseNet¹ 的發行,² 它是一個可以在瀏覽器裏對人體姿態進行實時估計的機器學習模型。點擊這裏在線體驗。html

PoseNet 使用單人姿態或多人姿態算法能夠檢測圖像和視頻中的人物形象 —— 所有在瀏覽器中完成。前端

那麼,姿態估計到底是什麼呢?姿態估計是指在圖像和視頻中檢測人物的計算機視覺技術,好比,能夠肯定某我的的肘部在圖像中的位置。須要澄清一點,這項技術並非識別圖像中是 —— 姿態估計不涉及任何我的身份信息。該算法僅僅是估計身體關鍵關節的位置。java

好吧,爲何這是使人興奮的開始?姿態估計有不少用途,從互動裝置反饋身體,到加強現實動畫健身用途等等。咱們但願藉助此模型激發更多的開發人員和製造商嘗試將姿態檢測應用到他們本身的獨特項目中。雖然許多同類姿態檢測系統也已經開源,但它們都須要專門的硬件和/或相機,以及至關多的系統安裝。 藉助運行在 TensorFlow.js 上的 PoseNet任何人只需擁有帶攝像頭的臺式機或者手機便可在瀏覽器中體驗這項技術。並且因爲咱們已經開源了這個模型,JavaScript 開發人員能夠用幾行代碼來修改和使用這個技術。更重要的是,這實際上能夠幫助保護用戶隱私。由於基於 TensorFlow.js 的 PoseNet 運行在瀏覽器中,任何姿態數據都不會離開用戶的計算機。python

在咱們深刻探討如何使用這個模型的細節以前,先向全部讓這個項目成爲可能的人們致意:論文對戶外多人姿態的精確估計PersonLab: 自下而上的局部幾何嵌入模型的人體姿態估計和實例分割的做者 George PapandreouTyler Zhu,以及 TensorFlow.js 庫背後的 Google Brain 小組的工程師 Nikhil ThoratDaniel Smilkovandroid


PoseNet 入門

PoseNet 能夠被用來估計單人姿態多人姿態,這意味着算法有一個檢測圖像/視頻中只有一我的的版本,和檢測多人的版本。爲何會有兩個版本?由於單人姿態檢測更快,更簡單,但要求圖像中只能有一個主體(後面會詳細說明)。咱們先說單體姿態,由於它更簡單易懂。ios

姿態估計總體來看主要有兩個階段:git

  1. 輸入一個經過卷積神經網絡反饋的 RGB 圖像
  2. 使用單人姿態或多人姿態解碼算法從模型輸出中解碼姿態,姿態置信得分關鍵點位置,以及關鍵點置信得分

等一下,全部這些關鍵詞指的是什麼?咱們看看一下最重要的幾個:es6

  • 姿態 - 從最上層來看,PoseNet 將返回一個姿態對象,其中包含每一個檢測到的人物的關鍵點列表和實例級別的置信度分數。

PoseNet 返回檢測到的每一個人的置信度值以及檢測到的每一個姿態關鍵點。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.orggithub

  • 姿態置信度分數 - 決定了對姿態估計的總體置信度。它介於 0.0 和 1.0 之間。它能夠用來隱藏分數不夠高的姿態。
  • 關鍵點 —— 估計的人體姿態的一部分,例如鼻子,右耳,左膝,右腳等。 它包含位置和關鍵點置信度分數。PoseNet 目前檢測到下圖所示的 17 個關鍵點:

PosNet 檢測到17個姿態關鍵點。

  • 關鍵點置信度得分 - 決定了估計關鍵點位置準確的置信度。它介於 0.0 和 1.0 之間。它能夠用來隱藏分數不夠高的關鍵點。
  • 關鍵點位置 —— 檢測到關鍵點的原始輸入圖像中的二維 x 和 y 座標。

第 1 部分:導入 TensorFlow.js 和 PoseNet 庫

不少工做都是將模型的複雜性抽象化並將功能封裝爲易於使用的方法。咱們看一下構建 PoseNet 項目的基礎知識。

該庫能夠經過 npm 安裝:

npm install @[tensorflow-models/posenet](https://www.npmjs.com/package/@tensorflow-models/posenet)
複製代碼

而後使用 es6 模塊導入:

import * as posenet from '@[tensorflow-models/posenet](https://www.npmjs.com/package/@tensorflow-models/posenet)';

const net = await posenet.load();
複製代碼

或經過頁面中的一個包:

<html>
  <body>
    <!-- Load TensorFlow.js -->
    <script src="[https://unpkg.com/@tensorflow/tfjs](https://unpkg.com/@tensorflow/tfjs)"></script>
    <!-- Load Posenet -->
    <script src="[https://unpkg.com/@tensorflow-models/posenet](https://unpkg.com/@tensorflow-models/posenet)"> </script>
    <script type="text/javascript"> posenet.load().then(function(net) { // posenet 模塊加載成功 }); </script>
  </body>
</html>
複製代碼

第 2a 部分:單人姿態估計

單人姿態估計算法用於圖像的示例。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.org

如前所述,單人姿態估計算法更簡單,速度更快。它的理想使用場景是當輸入圖像或視頻中心只有一我的。缺點是,若是圖像中有多我的,那麼來自兩我的的關鍵點可能會被估計成同一我的的姿態的一部分 —— 舉個例子,路人甲的左臂和路人乙的右膝可能會由該算法肯定爲屬於相同姿態而被合併。若是輸入圖像可能包含多人,則應該使用多人姿態估計算法。

咱們來看看單人姿態估計算法的輸入

  • 輸入圖像元素 —— 包含要預測圖像的 html 元素,例如視頻或圖像標記。重要的是,輸入的圖像或視頻元素應該是正方形的。
  • 圖像比例因子 —— 在 0.2 和 1 之間的數字。默認爲 0.50。在送入神經網絡以前如何縮放圖像。將此數字設置得較低以縮小圖像,並以精度爲代價增長經過網絡的速度。
  • 水平翻轉 —— 默認爲 false。表示是否姿態應該水平/垂直鏡像。對於視頻默認水平翻轉(好比網絡攝像頭)的視頻,應該設置爲 true,由於你但願姿態能以正確的方向返回。
  • 輸出步幅 —— 必須爲 32,16 或 8。默認 16。在內部,此參數會影響神經網絡中圖層的高度和寬度。在上層看來,它會影響姿態估計的精度速度。值越小精度越高,但速度更慢,值越大速度越快,但精度更低。查看輸出步幅對輸出質量的影響的最好方法是體驗這個單人姿態估計演示

下面讓咱們看一下單人姿態估計算法的輸出

  1. 一個包含姿態置信度得分和 17 個關鍵點數組的姿態。
  2. 每一個關鍵點都包含關鍵點位置和關鍵點置信度得分。一樣,全部關鍵點位置在輸入圖像的座標空間中都有 x 和 y 座標,而且能夠直接映射到圖像上。

這個段代碼塊顯示瞭如何使用單人姿態估計算法:

const imageScaleFactor = 0.50;
const flipHorizontal = false;
const outputStride = 16;

const imageElement = document.getElementById('cat');

// 加載 posenet 模型
const net = await posenet.load();

const pose = await net.estimateSinglePose(imageElement, scaleFactor, flipHorizontal, outputStride);
複製代碼

輸出姿態示例以下:

{
  "score": 0.32371445304906,
  "keypoints": [
    { // 鼻子
      "position": {
        "x": 301.42237830162,
        "y": 177.69162777066
      },
      "score": 0.99799561500549
    },
    { // 左眼
      "position": {
        "x": 326.05302262306,
        "y": 122.9596464932
      },
      "score": 0.99766051769257
    },
    { // 右眼
      "position": {
        "x": 258.72196650505,
        "y": 127.51624706388
      },
      "score": 0.99926537275314
    },
    ...
  ]
}
複製代碼

第 2b 部分:多人姿態估計

多人姿態估計算法應用於圖像的例子。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.org

多人姿態估計算法能夠估計圖像中的多個姿態/人物。它比單人姿態算法更復雜而且稍慢,但它的優勢是,若是圖片中出現多我的,他們檢測到的關鍵點不太可能與錯誤的姿態相關聯。出於這個緣由,即便用例是用來檢測單人的姿態,該算法也可能更合乎須要。

此外,該算法吸引人的特性是性能不受輸入圖像中人數的影響。不管是 15 人仍是 5 人,計算時間都是同樣的。

讓咱們看一下它的輸入

  • 輸入圖像元素 —— 與單人姿態估計相同
  • 圖像比例因子 —— 與單人姿態估計相同
  • 水平翻轉 —— 與單人姿態估計相同
  • 輸出步幅 —— 與單人姿態估計相同
  • 最大檢測姿態 —— 一個整數。默認爲 5,表示要檢測的姿態的最大數量。
  • 姿態置信分數閾值 —— 0.0 至 1.0。默認爲 0.5。在更深層次上,這將控制返回姿態的最低置信度分數。
  • 非最大抑制(NMS,Non-maximum suppression)半徑 —— 以像素爲單位的數字。在更深層次上,這控制了返回姿態之間的最小距離。這個值默認爲 20,這在大多數狀況下多是好的。能夠經過增長/減小,以濾除不太準確的姿態,但只有在調整姿態置信度分數沒法知足時才調整它。

查看這些參數有什麼影響的最好方法是體驗這個多人姿態估計演示

讓咱們看一下它的輸出

  • 以一系列姿態爲 resolvepromise
  • 每一個姿態包含與單人姿態估計算法中相同的信息。

這段代碼塊顯示瞭如何使用多人姿態估計算法:

const imageScaleFactor = 0.50;
const flipHorizontal = false;
const outputStride = 16;
// 最多 5 個姿態
const maxPoseDetections = 5;
// 姿態的最小置信度
const scoreThreshold = 0.5;
// 兩個姿態之間的最小像素距離
const nmsRadius = 20;

const imageElement = document.getElementById('cat');

// 加載 posenet
const net = await posenet.load();

const poses = await net.estimateMultiplePoses(
  imageElement, imageScaleFactor, flipHorizontal, outputStride,    
  maxPoseDetections, scoreThreshold, nmsRadius);
複製代碼

輸出數組的示例以下所示:

// 姿態/人的數組
[ 
  { // 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 演示了這多是一個很好的中止點。若是你想了解更多關於該模型和實現的技術細節,咱們邀請你繼續閱讀下文。


寫給好奇的人:技術深探

在本節中,咱們將介紹關於單人姿態估計算法的更多技術細節。在上層來看,這個過程以下所示:

使用 PoseNet 的單人姿態檢測器流程。

須要注意的一個重要細節是研究人員訓練了 PoseNet 的 ResNet 模型和 MobileNet 模型。雖然 ResNet 模型具備更高的準確性,但其大尺寸和多層的特色會使頁面加載時間和推導時間對於任何實時應用程序都不理想。咱們使用 MobileNet 模型,由於它是爲移動設備而設計的。

從新審視單人姿態估計算法

處理模型輸入:輸出步幅的解釋

首先,咱們將說明如何經過討論輸出步幅來得到 PoseNet 模型輸出(主要是熱圖和偏移矢量)。

比較方便地是,PoseNet 模型是圖像大小不變的,這意味着它能以與原始圖像相同的比例預測姿態位置,而無論圖像是否縮小。這意味着 PoseNet 能夠經過設置上面咱們在運行時提到的輸出步幅以犧牲性能得到更高的精度

輸出步幅決定了咱們相對於輸入圖像大小縮小輸出的程度。它會影響圖層和模型輸出的大小。輸出步幅越大,網絡中的層和輸出的分辨率越小,準確性也越低。在此實現中,輸出步幅能夠爲 8,16 或 32。換句話說,輸出步幅爲 32 將輸出最快可是精度最低,而 8 的精度最高可是最慢。咱們建議從 16 開始。

輸出步幅決定了輸出相對於輸入圖像的縮小程度。較高的輸出步幅會更快,但會致使精度較低。

本質是,當輸出步幅設置爲 8 或 16 時,層中的輸入量減小使得能夠建立更大的輸出分辨率。而後使用 Atrous 卷積來使後續圖層中的卷積濾波器具備更寬的視野(當輸出步幅爲 32 時,不會應用 atrous 卷積)。雖然 Tensorflow 支持 atrous 卷積,但 TensorFlow.js 不支持,因此咱們添加了一個 PR 來包含這個。

模型輸出:熱圖和偏移矢量

當 PoseNet 處理圖像時,事實上返回的是熱圖以及偏移矢量,能夠解碼以找到圖像中與姿態關鍵點對應的高置信度區域。咱們將在一分鐘內討論它們各自的含義,但如今下面的插圖以高級方式捕獲每一個姿態關鍵點與一個熱圖張量和一個偏移矢量張量的關聯。

PoseNet 返回的 17 個姿態關鍵點中的每個都與一個熱圖張量和一個偏移矢量張量相關聯,用於肯定關鍵點的確切位置。

這兩個輸出都是具備高度和寬度的 3D 張量,咱們將其稱爲分辨率。分辨率由輸入圖像大小和輸出步幅根據如下公式肯定:

Resolution = ((InputImageSize - 1) / OutputStride) + 1

// 示例:寬度爲 225 像素且輸出步幅爲 16 的輸入圖像產生輸出分辨率爲 15
// 15 = ((225 - 1) / 16) + 1
複製代碼

熱圖

每一個熱圖是尺寸 resolution x resolution x 17 的 3D 張量,由於 17 是 PoseNet 檢測到的關鍵點的數量。例如,圖像大小爲 225,輸出步幅爲 16,那麼就是 15 x 15 x 17。第三維(17)中的每一個切片對應於特定關鍵點的熱圖。該熱圖中的每一個位置都有一個置信度分數,這是該類型關鍵點的一部分在該位置的機率。它能夠被認爲是原始圖像被分解成 15 x 15 網格,其中熱圖分數提供了每一個網格中每一個關鍵點存在機率的等級。

偏移矢量

每一個偏移矢量都是尺寸 resolution x resolution x 34 的 3D 張量,其中 34 是關鍵點數* 2。圖像大小爲 225,輸出步幅爲 16 時,它是 15 x 15 x 34。因爲熱圖是關鍵點位置的近似值,因此偏移矢量在位置上對應於熱圖中的點,用於遍歷熱圖點對應的向量,從而預測關鍵點的確切位置。偏移矢量的前 17 個切片包含矢量的 x 座標和後 17 個包含 y 座標。偏移矢量大小與原始圖像具備相同的比例

根據模型的輸出估計姿態

圖像經過模型饋送後,咱們執行一些計算來從輸出中估計姿態。例如,單人姿態估計算法返回姿態置信度分數,它包含關鍵點數組(以各部分的 ID 做索引),每一個關鍵點具備置信度分數和 x,y 位置。

爲了得到姿態的關鍵點:

  1. 調用熱圖的 sigmoid 方法,以得到分數。 scores = heatmap.sigmoid()
  2. argmax2d 是根據關鍵點置信度得分來得到熱圖中 x 和 y 索引,取每一個部分的得分最高者,通常也是該部分最有可能存在的地方。這會產生一個尺寸爲 17 x 2 的張量,每一行都是每部分得分最高的熱圖中的 y 和 x 索引。 heatmapPositions = scores.argmax(y, x)
  3. 每部分的偏移矢量經過從該部分的熱圖中對應 x 和 y 索引的偏移量中獲取 x 和 y。這會產生 17 x 2 的張量,每行都是相應關鍵點的偏移向量。例如,對於索引爲 k 的部分,當熱圖位置爲 y 和 x 時,偏移矢量爲: offsetVector = [offsets.get(y, x, k), offsets.get(y, x, 17 + k)]
  4. 爲了得到關鍵點,將每部分的熱圖 x 和 y 乘以輸出步幅,而後將其添加到它們對應的偏移向量中,該向量與原始圖像具備相同的比例。 keypointPositions = heatmapPositions * outputStride + offsetVectors
  5. 最後,每一個關鍵點置信度分數是其熱圖位置的置信度分數。該姿態的置信度得分是關鍵點的評分的平均值。

多人姿態估計

多人姿態估計算法的細節超出了本文的範圍。該算法的主要不一樣之處在於它使用貪婪過程經過沿着基於部分圖的位移矢量將關鍵點分組爲姿態。具體來講,它使用研究論文 PersonLab: 自下而上的局部幾何嵌入模型的人體姿態估計和實例分割中的快速貪婪解碼算法。有關多人姿態算法的更多信息,請閱讀完整的研究論文或查看代碼


咱們但願隨着愈來愈多的模型被移植到 TensorFlow.js,機器學習的世界變得對更容易被新的開發者和製造者接受,更受歡迎和更有趣。基於 TensorFlow.js 的 PoseNet 是實現這一目標的一個小小嚐試。咱們很樂意看到你作出了什麼 —— 不要忘記使用 #tensorflowjs 和 #posenet 分享您的精彩項目!


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索