使用TensorFlow.js在瀏覽器中實時估計人體姿態

發佈者:Dan Oved,谷歌創意實驗室的自由創意技術員,紐約大學ITP的研究生。

編輯和插圖:艾琳阿爾瓦拉多,創意技術師和亞歷克西斯加洛,自由平面設計師,在谷歌創意實驗室。

與Google Creative Lab合作,我很高興地宣佈發佈TensorFlow.js版本的PoseNet,一個允許在瀏覽器中進行實時人體姿勢估計的機器學習模型。在這裡試一試現場演示。

使用TensorFlow.js在瀏覽器中實時估計人體姿態

使用TensorFlow.js在瀏覽器中實時估計人體姿態

PoseNet可以使用單一姿勢或多姿勢算法檢測圖像和視頻中的人物-所有這些都可以在瀏覽器中進行

那麼什麼是姿勢估計呢?姿勢估計是指計算機視覺技術,它可以檢測圖像和視頻中的人物,以便確定,例如,某人的肘部在圖像中出現的位置。更清楚的是,這項技術並沒有識別出圖像中的人,也沒有與姿勢檢測相關的個人識別信息。算法只是簡單地估計關鍵身體關節的位置。

好吧,為什麼一開始就讓人興奮?姿勢估計有很多用途,從對身體做出反應的交互式 裝置到增強現實、動畫、健身用途等等。我們希望這個模型的可訪問性能夠激勵更多的開發者和製作者在他們自己獨特的項目中進行姿勢檢測的實驗和應用。雖然許多替代姿態檢測系統都是開源的,但所有這些系統都需要專門的硬件和或攝像頭,以及相當多的系統設置。隨著PoseNet在TensorFlow.js上的運行,任何擁有一個配備了不錯的網絡攝像頭的桌面或手機的人都可以在網絡瀏覽器中體驗這項技術。由於我們已經開放了該模型的源代碼,Javascript開發人員只需幾行代碼就可以修補並使用這項技術。此外,這實際上有助於保護用戶隱私。由於TensorFlow.js上的PoseNet在瀏覽器中運行,因此任何姿勢數據都不會離開用戶的計算機。

在我們深入研究如何使用這個模型之前,首先向所有使這個項目成為可能的人歡呼:George Papandreou和Tyler Zhu,谷歌的研究人員,他們是論文的幕後推動者致力於精確的野外多人姿勢估計和PersonLab:基於自下而上部分的個人姿勢估計和實例分割,幾何嵌入模型,Nikhil Thorat和Daniel Smilkov,TensorFlow.js庫背後的Google Brain團隊的工程師。

PoseNet可用於估計單個姿勢或多個姿勢,這意味著算法的一個版本只能檢測圖像/視頻中的一個人,而另一個版本可以檢測圖像/視頻中的多個人。為什麼有兩個版本?單人姿勢檢測器更快更簡單,但只需要圖像中的一個對象(稍後會詳細介紹)。我們先介紹一下單體式,因為它更容易跟隨。

在高層次上,姿態估計分為兩個階段:

  1. 通過卷積神經網絡輸入RGB圖像
  2. 使用單姿態或多姿態解碼算法對模型輸出的姿態(Pose)、姿態置信度得分(Pose confidence score)、關鍵點位置(Keypoint Position)和關鍵點置信度得分(Keypoint Confidence Score)進行解碼。

等等,這些關鍵詞是什麼意思?讓我們回顧一下最重要的:

  • 姿態(Pose) — 在最高級別,PoseNet將返回一個pose對象,該對象包含每個檢測到的人的關鍵點列表和實例級置信度分數。 PoseNet為檢測到的每個人以及檢測到的每個姿勢關鍵點返回置信值。圖片來源:“Microsoft Coco:當前數據集中的公共對象”, https://cocodataset.org.
  • 姿態置信度得分(Pose confidence score) — 這決定了姿態估計的總體置信度。範圍在0.0到1.0之間。它可以用來隱藏被認為不夠強壯的姿勢。
  • 關鍵點(Keypoint) — 估計的人的姿勢的一部分,如鼻子、右耳、左膝、右腳等。它包含一個位置和一個關鍵點的信心得分。PoseNet目前檢測到17個關鍵點,如下圖所示:

PoseNet檢測到1 7個姿勢關鍵點

  • 關鍵點置信度得分(Keypoint Confidence Score) — 這將確定估計的關鍵點位置是否準確的置信度。範圍在0.0到1.0之間。它可以用來隱藏被認為不夠強大的關鍵點
  • 關鍵點位置(Keypoint Position) — 檢測到關鍵點的原始輸入圖像中的二維x和y座標。

在抽象模型的複雜性和將功能封裝為易於使用的方法方面做了大量工作。讓我們回顧一下如何設置PoseNet項目的基礎知識。

可以使用npm安裝庫:

npm install @tensorflow-models/posenet

並使用es6模塊導入:

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

或者通過頁面中的捆綁:

<code>





/<code>
使用TensorFlow.js在瀏覽器中實時估計人體姿態

應用於圖像的示例單人姿勢估計算法。圖片來源: https://cocodataset.org

如前所述,單姿態估計算法是兩種算法中比較簡單和快速的。它的理想用例是當一個輸入圖像或視頻中只有一個人的時候。缺點是,如果一個圖像中有多個人,兩個人的關鍵點很可能被估計為同一個姿勢的一部分,這意味著,例如,該算法可能將第一個人的左臂和第二個人的右膝合併為屬於同一姿勢。如果輸入圖像可能包含多人,則應使用多姿態估計算法。

讓我們回顧一下單姿態估計算法的輸入

  • 輸入圖像元素(Input image element) — 一個html元素,它包含一個要預測姿勢的圖像,例如視頻或圖像標記。重要的是,輸入的圖像或視頻元素應該是方形的
  • 圖像比例因子(Image scale factor) — 介於0.2和1之間的數字。默認為0.50。在通過網絡傳送圖像之前,通過什麼來縮放圖像。將此數字設置得更低,以縮小圖像並在通過網絡傳輸時提高速度,但會降低精度
  • 水平翻轉(Flip horizontal) — 默認為false。如果姿勢應該水平翻轉/鏡像。對於默認水平翻轉視頻(即網絡攝像頭)的視頻,這應該設置為true,並且您希望以正確的方向返回姿勢
  • 輸出跨距(Output stride) — 必須是32、16或8。默認為16。在內部,該參數影響神經網絡中層的高度和寬度。在較高的水平上,它會影響姿態估計的精度和速度。輸出跨距的值越低精度越高但速度越慢,值越高速度越快但精度越低。查看輸出跨距對輸出質量影響的最佳方法是使用單姿勢估計演示

現在讓我們回顧一下單姿態估計算法的輸出:

  • 一種姿勢,包含一個姿勢置信度得分和一個由17個關鍵點組成的數組。
  • 每個關鍵點包含一個關鍵點位置和一個關鍵點信心得分。同樣,所有的關鍵點位置在輸入圖像空間中都有x和y座標,並且可以直接映射到圖像上。

此短代碼塊顯示瞭如何使用單姿態估計算法:

<code>    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);/<code>

示例輸出姿勢如下所示:

<code>    {
"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
},
...
]
}/<code>
使用TensorFlow.js在瀏覽器中實時估計人體姿態

應用於圖像的多人姿態估計算法示例。圖片來源:https://cocodataset.org

多人姿態估計算法可以估計圖像中的多個姿態。它比單一姿勢算法更復雜,速度稍慢,但它的優點是,如果一張圖片中出現多個人,他們檢測到的關鍵點就不太可能與錯誤的姿勢相關聯。因此,即使用例是為了檢測一個人的姿勢,這個算法可能更可取。

此外,該算法的一個吸引人的特性是性能不受輸入圖像中的人數的影響。無論是15人檢測還是5人檢測,計算時間都是一樣的。

讓我們回顧一下輸入:

  • 輸入圖像元素(Input image element) — 與單姿態估計相同
  • 圖像比例因子(Image scale factor) — 與單姿態估計相同
  • 水平翻轉(Flip horizontal) — 與單姿態估計相同
  • 輸出跨距(Output stride) — 與單姿態估計相同
  • 最大姿態檢測(Maximum pose detections) — 一個整數。默認為5。要檢測的pose的最大數目
  • 姿勢置信得分閾值(Pose confidence score threshold) — 0.0到1.0。默認為0.5。在高水平上,這可以控制返回pose的最小置信分數
  • 非最大抑制(NMS) — 半徑 以像素為單位的數字。在高級別上,這控制返回的姿勢之間的最小距離。這個值默認為20,這在大多數情況下可能是好的。它應該增加/減少,作為一種過濾不太準確的姿勢的方法,但只有在調整姿勢信心分數不夠好的情況下。

要了解這些參數的效果,最好的方法是使用多姿態估計演示。

讓我們回顧一下輸出:

  • 輸出一系列姿勢的Promise
  • 每個姿勢包含的信息與單人估計算法中描述的相同。

此短代碼塊演示如何使用多姿態估計算法:

<code>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);/<code>

姿勢的示例輸出數組如下所示:

<code>// 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
},
...
]
},
...
]/<code>

如果你已經讀了這麼多,你知道的足夠多了,可以開始使用PoseNet演示了。這可能是一個很好的停止點。如果您想了解更多關於模型和實現的技術細節,我們邀請您繼續閱讀下面的內容。

在這一節中,我們將討論關於單姿態估計算法的更多技術細節。在較高層次上,流程如下:

使用TensorFlow.js在瀏覽器中實時估計人體姿態

使用PoseNet的單人姿勢檢測器管道


需要注意的一個重要細節是,研究人員訓練了PoseNet的ResNet和MobileNet模型。ResNet模型具有較高的精度,但由於其規模大、層次多,使得頁面加載時間和推理時間都不適合任何實時應用。我們採用了MobileNet模型,因為它是為在移動設備上運行而設計的。

處理模型輸入:輸出步幅(output strides)的解釋

首先,我們將討論如何通過輸出步幅獲得PoseNet模型輸出(主要是熱圖和偏移向量)。

方便的是,PoseNet模型是圖像大小不變的,這意味著無論圖像是否縮小,它都可以在與原始圖像相同的尺度上預測姿態位置。這意味著PoseNet可以通過在運行時設置上面提到的輸出步幅來配置為以犧牲性能為代價具有更高的精度。

輸出跨距決定了我們相對於輸入圖像大小縮小輸出的程度。它影響圖層的大小和模型輸出。輸出步長越大,網絡層和輸出層的分辨率就越小,相應的精度也就越低。在這個實現中,輸出跨距的值可以是8、16或32。換句話說,32的輸出步幅將導致最快的性能,但精度最低;8的輸出步幅將導致最高的精度,但性能最低。我們建議從16開始。

使用TensorFlow.js在瀏覽器中實時估計人體姿態

輸出步幅決定了我們相對於輸入圖像大小縮小輸出的程度。輸出步幅越大,速度越快,但精度越低

在引擎蓋下面,當輸出跨距設置為8或16時,層中的輸入跨距量減少,以創建更大的輸出分辨率。然後使用阿託魯斯卷積使隨後層中的卷積濾波器具有更寬的視野(當輸出跨距為32時不應用阿託魯斯卷積)。雖然Tensorflow支持atrus卷積,但Tensorflow.js不支持,因此我們添加了一個PR來包含這個。

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

當PoseNet處理一個圖像時,實際上返回的是一個熱圖偏移向量,這些向量可以被解碼以在圖像中找到與姿勢關鍵點相對應的高置信度區域。我們將在一分鐘內討論每一個關鍵點的含義,但現在下面的插圖從高層捕捉到每個姿勢關鍵點是如何與一個熱圖張量和一個偏移向量張量相關聯的。

使用TensorFlow.js在瀏覽器中實時估計人體姿態

PoseNet返回的17個姿勢關鍵點中每一個都與一個熱圖張量和一個用於確定關鍵點精確位置的偏移向量張量相關聯

兩個輸出都是具有高度和寬度的三維張量,我們將其稱為分辨率。根據以下公式,分辨率由輸 入圖像大小和輸出步幅確定:

<code>Resolution = ((InputImageSize - 1) / OutputStride) + 1
// Example: an input image with a width of 225 pixels and an output
// stride of 16 results in an output resolution of 15
// 15 = ((225 - 1) / 16) + 1/<code>

熱圖

由於17是PoseNet檢測到的關鍵點數量,因此每個熱圖都是一個大小分辨率x分辨率x 17的3D張量。例如,如果圖像大小為225,輸出跨距為16,則為15x15x17。三維(共17個)中的每個切片對應於特定關鍵點的熱圖。熱圖中的每個位置都有一個置信分數,這是該關鍵點類型的一部分存在於該位置的概率。它可以被認為是原始圖像被分解成一個15x15的網格,其中熱圖分數提供了每個網格正方形中每個關鍵點存在的可能性的分類。

偏移矢量

每個偏移向量是尺寸分辨率x分辨率x 34的3D張量,其中34是關鍵點的數目*2。圖像大小為225,輸出跨距為16,這將是15x15x34。由於熱圖是關鍵點所在位置的近似值,因此偏移向量對應於熱圖點的位置,並通過從對應的熱圖點沿向量移動來預測關鍵點的準確位置。偏移向量的前17個切片包含向量的x,後17個切片包含向量的y。偏移向量大小與原始圖像的比例相同。

根據模型輸出估計姿態

在圖像通過模型後,我們進行一些計算來估計輸出的姿態。例如,單姿態估計算法返回一個姿態置信度得分,它本身包含一個關鍵點數組(由部件ID索引),每個關鍵點都有一個置信度得分和x,y位置。要獲取姿勢的關鍵點:

  1. 在熱圖上使用sigmoid激活函數以獲得分數。 scores = heatmap.sigmoid()
  2. argmax2d對關鍵點信心得分(keypoint confidence scores)進行處理,以獲得熱圖中的x和y指數,每個部分的得分最高,這實際上是該部分最有可能存在的地方。這將產生17x2大小的張量,其中每一行是熱圖中的y和x索引,每個部分的得分最高。 heatmapPositions = scores.argmax(y, x)
  3. 通過從對應於該零件的熱圖中的x和y索引的偏移中獲取x和y來檢索每個零件的偏移向量。這會產生17x2大小的張量,每一行是對應關鍵點的偏移向量。例如,對於索引k處的零件,當熱圖位置為y和d時,偏移矢量為: 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分享你的精彩項目!


分享到:


相關文章: