- 原文地址:Real-time Human Pose Estimation in the Browser with TensorFlow.js
- 原文做者:Dan Oved
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:NoName4Me
- 校對者:luochen1992、isiyin
發佈者:Dan Oved,谷歌創意實驗室自由創意技術專家,紐約大學 ITP 研究生。 編輯和插圖:創意技術專家 Irene Alvarado 和谷歌創意實驗室自由平面設計師 Alexis Gallo。javascript
在與谷歌創意實驗室的合做中,我很高興地宣佈 TensorFlow.js 版 PoseNet¹ 的發行,² 它是一個可以在瀏覽器裏對人體姿態進行實時估計的機器學習模型。點擊這裏在線體驗。html
PoseNet 使用單人姿態或多人姿態算法能夠檢測圖像和視頻中的人物形象 —— 所有在瀏覽器中完成。前端
那麼,姿態估計到底是什麼呢?姿態估計是指在圖像和視頻中檢測人物的計算機視覺技術,好比,能夠肯定某我的的肘部在圖像中的位置。須要澄清一點,這項技術並非識別圖像中是誰 —— 姿態估計不涉及任何我的身份信息。該算法僅僅是估計身體關鍵關節的位置。java
好吧,爲何這是使人興奮的開始?姿態估計有不少用途,從互動裝置反饋給身體,到加強現實,動畫,健身用途等等。咱們但願藉助此模型激發更多的開發人員和製造商嘗試將姿態檢測應用到他們本身的獨特項目中。雖然許多同類姿態檢測系統也已經開源,但它們都須要專門的硬件和/或相機,以及至關多的系統安裝。 藉助運行在 TensorFlow.js 上的 PoseNet,任何人只需擁有帶攝像頭的臺式機或者手機便可在瀏覽器中體驗這項技術。並且因爲咱們已經開源了這個模型,JavaScript 開發人員能夠用幾行代碼來修改和使用這個技術。更重要的是,這實際上能夠幫助保護用戶隱私。由於基於 TensorFlow.js 的 PoseNet 運行在瀏覽器中,任何姿態數據都不會離開用戶的計算機。python
在咱們深刻探討如何使用這個模型的細節以前,先向全部讓這個項目成爲可能的人們致意:論文對戶外多人姿態的精確估計 和 PersonLab: 自下而上的局部幾何嵌入模型的人體姿態估計和實例分割的做者 George Papandreou 和 Tyler Zhu,以及 TensorFlow.js 庫背後的 Google Brain 小組的工程師 Nikhil Thorat 和 Daniel Smilkov。android
PoseNet 能夠被用來估計單人姿態或多人姿態,這意味着算法有一個檢測圖像/視頻中只有一我的的版本,和檢測多人的版本。爲何會有兩個版本?由於單人姿態檢測更快,更簡單,但要求圖像中只能有一個主體(後面會詳細說明)。咱們先說單體姿態,由於它更簡單易懂。ios
姿態估計總體來看主要有兩個階段:git
等一下,全部這些關鍵詞指的是什麼?咱們看看一下最重要的幾個:es6
PoseNet 返回檢測到的每一個人的置信度值以及檢測到的每一個姿態關鍵點。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.org。github
PosNet 檢測到17個姿態關鍵點。
不少工做都是將模型的複雜性抽象化並將功能封裝爲易於使用的方法。咱們看一下構建 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>
複製代碼
單人姿態估計算法用於圖像的示例。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.org。
如前所述,單人姿態估計算法更簡單,速度更快。它的理想使用場景是當輸入圖像或視頻中心只有一我的。缺點是,若是圖像中有多我的,那麼來自兩我的的關鍵點可能會被估計成同一我的的姿態的一部分 —— 舉個例子,路人甲的左臂和路人乙的右膝可能會由該算法肯定爲屬於相同姿態而被合併。若是輸入圖像可能包含多人,則應該使用多人姿態估計算法。
咱們來看看單人姿態估計算法的輸入:
下面讓咱們看一下單人姿態估計算法的輸出:
這個段代碼塊顯示瞭如何使用單人姿態估計算法:
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
},
...
]
}
複製代碼
多人姿態估計算法應用於圖像的例子。圖片來源:「Microsoft Coco:上下文數據集中的通用對象」,cocodataset.org。
多人姿態估計算法能夠估計圖像中的多個姿態/人物。它比單人姿態算法更復雜而且稍慢,但它的優勢是,若是圖片中出現多我的,他們檢測到的關鍵點不太可能與錯誤的姿態相關聯。出於這個緣由,即便用例是用來檢測單人的姿態,該算法也可能更合乎須要。
此外,該算法吸引人的特性是性能不受輸入圖像中人數的影響。不管是 15 人仍是 5 人,計算時間都是同樣的。
讓咱們看一下它的輸入:
查看這些參數有什麼影響的最好方法是體驗這個多人姿態估計演示。
讓咱們看一下它的輸出:
resolve
的 promise
。這段代碼塊顯示瞭如何使用多人姿態估計算法:
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 位置。
爲了得到姿態的關鍵點:
scores = heatmap.sigmoid()
heatmapPositions = scores.argmax(y, x)
offsetVector = [offsets.get(y, x, k), offsets.get(y, x, 17 + k)]
keypointPositions = heatmapPositions * outputStride + offsetVectors
多人姿態估計算法的細節超出了本文的範圍。該算法的主要不一樣之處在於它使用貪婪過程經過沿着基於部分圖的位移矢量將關鍵點分組爲姿態。具體來講,它使用研究論文 PersonLab: 自下而上的局部幾何嵌入模型的人體姿態估計和實例分割中的快速貪婪解碼算法。有關多人姿態算法的更多信息,請閱讀完整的研究論文或查看代碼。
咱們但願隨着愈來愈多的模型被移植到 TensorFlow.js,機器學習的世界變得對更容易被新的開發者和製造者接受,更受歡迎和更有趣。基於 TensorFlow.js 的 PoseNet 是實現這一目標的一個小小嚐試。咱們很樂意看到你作出了什麼 —— 不要忘記使用 #tensorflowjs 和 #posenet 分享您的精彩項目!
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。