posenet.load.then(function(net) {
// posenet model loaded
});
第二步(上):單人姿態估計
如前所述,單姿態估計算法是兩者中較簡單也較快速的。理想的使用場景是當輸入的圖像或視頻中只有一個人時使用這種算法。其缺點在於,如果圖像中有多個人,則來自兩個人的關鍵點可能被估計為同一個姿態的一部分——這意味著,A 的左臂和 B 的右膝可能被該算法歸為同一姿態。因此,如果輸入的圖像可能包含多人,則應當使用多姿態估計算法。
讓我們看一下單姿態估計算法的輸入:
輸入圖像元素——一種 html 元素,包含要為諸如視頻或圖像標籤預測姿態的圖像。重點是,輸入的圖像或視頻元素應為正方形。
圖像比例因子——介於 0.2~1 的數字,默認值為 0.50。用於在向網絡輸送圖像之前,對圖像進行縮放。將此數字設置得較低,以縮小圖像,提高輸送至網絡的速度,不過這是以準確率為代價的。
水平翻轉——默認值為 false,在姿態需要水平翻轉/鏡像的情況下。而對於默認情況為水平翻轉的視頻(即網絡攝像頭),且你希望姿態以正確方向返回,應將水平翻轉設置為 true。
輸出步幅——必須為 32、16 或 8。默認值為 16。從內部來看,該參數影響神經網絡中層的高度和寬度。在較高層次上,它會影響姿態估計的準確率和速度。輸出步幅的值越低,準確率越高,但速度越慢;輸出步幅值越高,速度越快,但準確率越低。查看輸出步幅對輸出質量影響的最佳方法是使用單姿態估計算法 demo:https://storage.googleapis.com/tfjs-models/demos/posenet/camera.html。
現在,我們看一下單姿態估計算法的輸出:
每個姿態包含姿態置信度得分和 17 個關鍵點。
每個關鍵點包含其位置和置信度得分。同樣,所有關鍵點位置在輸入圖像空間中都有 xy 座標,並且可以直接映射到圖像上。
以下簡短的代碼塊展示瞭如何使用單姿態估計算法:
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
},
...
]
}
第二步(下):多人姿態估計
多人姿態估計算法可以估計一個圖像中的多個人/姿態。它比單姿態算法更復雜更慢,但其優點是,如果一張圖像中出現多個人物,則檢測到的關鍵點不太可能關聯至不匹配的姿態。因此,即使是用來檢測一個人的姿態,該算法可能也更理想。
此外,該算法還有一個不錯的特性——其性能不受輸入圖像中人數的影響。無論有 15 個還是 5 個人要檢測,它的計算時間都一樣。
我們來看一下輸入:
輸入圖像元素——與單姿態估計相同。
圖像比例因子——與單姿態估計相同。
水平翻轉——與單姿態估計相同。
輸出步幅——與單姿態估計相同。
最大姿態檢測——整數,默認值為 5。表示可檢測的最大姿態數量。
姿態置信度得分閾值——0.0~1.0,默認值為 0.5。在較高層次上,它控制返回姿態的最小置信度得分。
非極大值抑制(NMS)半徑——以像素為單位。在較高水平上,它控制返回姿態之間的最小距離。默認值為 20,適用於大多數情況。只有在調整姿態置信度得分不夠好的情況下,應該增加/減少其數值,以過濾不太精確的姿態。
查看這些參數影響的最佳方法是使用多姿態估計 demo(https://storage.googleapis.com/tfjs-models/demos/posenet/camera.html)。
讓我們查看一下輸出:
解決多姿態估計問題。
每個姿態包含與單人姿態估計算法相同的信息。
以下簡短的代碼塊展示瞭如何使用多姿態估計算法:
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 demo 已經有了足夠的瞭解,閱讀止於此處也是一個不錯的選擇。但如果想進一步瞭解模型和實現的技術細節,可繼續閱讀以下內容。
對於好奇的大腦來說,這是一次技術深潛
本節將深入討論單姿態估計算法的更多技術細節。在較高層次上,其流程如下所示:
使用 PoseNet 的單人姿態檢測器流程
需要注意的一個重要細節是,研究人員同時訓練了 PoseNet 的 ResNet 模型和 MobileNet 模型。雖然 ResNet 模型具有較高的準確率,但其龐大體積和多層結構使得頁面加載時間和推斷時間對於任何實時應用來說都不太理想。TensorFlow 採用了 MobileNet 模型,因為它是為移動設備運行而設計的。
再回到單姿態估計算法
處理模型輸入:對輸出步幅的解釋
首先,我們將通過討論輸出步幅來了解 PoseNet 模型輸出(主要是熱圖和偏移向量)。
方便的一點是,PoseNet 模型要求圖像尺寸不變,這意味著它可以預測與原始圖像相同比例的姿態位置,而不管圖像是否被縮小。這也意味著 PoseNet 可以通過在運行時設置輸出步幅,以性能為代價獲取更高的準確率。
輸出步幅決定了輸出比輸入圖像縮小的程度,它會影響層的大小和模型輸出。輸出步幅越高,網絡中層的分辨率和輸出及其準確率就越小。在此實現中,輸出步幅的值可以是 8、16 或 32。換句話說,32 的輸出步幅將造成最快的性能、最低的準確率,而 8 將導致最高的準確率、最慢的性能。我們建議從 16 開始。
輸出步幅決定了輸出比輸入圖像縮小的程度。輸出步幅越高,速度越快,但準確率越低。
實現過程中,當輸出步幅被設置為 8 或 16 時,各層中的輸入步幅將減少,以創建更大的輸出分辨率。然後使用用空洞卷積(atrous convolution)使後續層中的卷積濾波器具有更寬的視野(當輸出步幅為 32 時,不使用空洞卷積)。雖然 TensorFlow 支持空洞卷積,但 TensorFlow.js 並不支持,因此我們添加了一個 PR 來彌補這一點。
模型輸出:熱圖和偏移向量(Offset Vector)
當 PoseNet 處理圖像時,實際上返回的是熱圖和偏移向量,我們可對其進行解碼,以在圖像中找到對應姿態關鍵點的高置信度區域。下圖展示了在較高層次,每個姿態關鍵點與熱圖張量和偏移向量張量的關聯。
PoseNet 返回的 17 個姿態關鍵點中每一個都與用於確定關鍵點確切位置的熱圖張量和偏移向量張量相關聯。
這兩個輸出都是三維張量,其高度和寬度稱為分辨率。根據以下公式,分辨率由輸入圖像大小和輸出步幅確定:
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
熱圖
每個熱圖是尺寸為分辨率 x 分辨率 x 17 的 3D 張量,17 是 PoseNet 檢測到的關鍵點的數量。例如,對於 225 的圖像大小和 16 的輸出步幅,熱圖大小將是 15 x15x 17。(17 箇中)第三維的每個切片圖對應特定關鍵點的熱圖。熱圖中每個位置具有置信度得分,即該關鍵點類型的一部分存在於該位置中的概率。我們可以將其看作是把原始圖像分割成 15x 15 網格,其中熱圖得分提供了每個關鍵點在每個網格正方形中存在可能性的分類。
偏移向量
每個偏移向量是尺寸為分辨率 x 分辨率 x 34 的 3D 張量,34 是關鍵點數量*2 得出的數字。如果圖像大小為 225,輸出步幅為 16,則該值為 15x15x34。由於熱圖是關鍵點所在位置的近似,因此偏移向量在位置上對應熱圖點,並且用於預測關鍵點的確切位置,如通過從相應熱圖點沿著向量行進。偏移向量的前 17 個切片圖包含向量的 x,後 17 個切片包含 y。偏移向量大小與原始圖像的比例相同。
根據模型的輸出估計姿態
在圖像輸入到模型後,我們執行一些計算以從輸出估計姿態。例如,單姿態估計算法返回姿態置信度得分,該得分本身包含多個關鍵點(由 part ID 索引),每個關鍵點具有置信度得分和 xy 位置。
要獲取姿態的關鍵點:
1. 在熱圖上進行 sigmoid 激活函數操作,獲得得分。
scores = heatmap.sigmoid
2. 對關鍵點置信度得分執行 argmax2d,獲得熱圖中的 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: Person Pose Estimation and Instance Segmentation with a Bottom-Up, Part-Based, Geometric Embedding Model》中的快速貪婪解碼算法(fast greedy decoding algorithm)。有關多姿態算法的更多信息,請閱讀完整論文或查看代碼。代碼地址:https://github.com/tensorflow/tfjs-models/tree/master/posenet/src。
原文鏈接:https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5
✄------------------------------------------------
廣告&商務合作:[email protected]
閱讀更多 坤艮機器之心 的文章
關鍵字: 瀏覽器 開發者 JavaScript