人體姿態檢測概述

人體姿態檢測分爲兩種方式,一種是自頂向下,一種是自底向上。

自頂向下:

先找人,將人體進行目標框檢測,再在目標框內去找人體的關鍵點,再進行關鍵點的連接。

自底向上:

先找點,後歸納。這裏我們不需要先找人的目標框。我們要找到圖像中的所有人體關鍵點,再把屬於同一個人的關鍵點歸爲一類。

關鍵點檢測評價體系

在目標框檢測和實例分割或者語義分割中,使用的是IoU,上圖中藍色的部分代表ground truth。綠色部分是預測出來的部分。但是人體關鍵點檢測就不是IoU了,而是OKS。

  • OKS(Object Keypoint Similarity相似度)

對於我們的人體關鍵點檢測的時候,我們對關鍵點標註的格式是這樣的

這裏x、y代表座標,v代表是否可見。具體的意義如下:

  1. v=0,未標註點
  2. v=1,已標註,但不可見
  3. v=2,已標註並圖像可見

OKS的公式如下

  1. k表示第i 個骨骼點的歸一化因子,這個因子是通過對所有的數據集中所有ground truth計算標準差而得到的,反映出當前骨骼點對整體的影響程度。值越大,說明在整個數據集中對這個點的標註效果越差;值越小,說明整個數據集中對這個點的標註效果越好。
  2. \sf d_i是標註和預測關鍵點之間的歐式距離。
  3. \sf sk_i爲標準差,s^2是用來做尺度歸一化,k^2是數據集標註的標準差。
  4. 當完美預測的時候OKS=1,當預測與ground truth差距比較大的時候,OKS=0

以上圖中人眼爲例,藍色的代表ground truth,紅色部分表示預測的位置,我們可以看到預測值圍繞ground truth成一個正態分佈。對比正態分佈的概率密度函數也可以看的出來

那麼OKS的整個式子代表着所有預測值的概率分佈與ground truth的比值。

對關鍵點因爲是人工標註,所以每個人的標註可能各不相同,經過對大量圖像的統計,這些標註會呈現一個正態分佈。如果是對眼睛的標註和對臀部的標註,那麼對眼睛的標註的尺度更小,而對臀部的標註的尺度更大。換句話說我們會對眼睛的要求比臀部更高,這個就是s的意義。

k是一個常數。這樣就會對不同的關鍵點的範圍的要求不同。

這一個一個圓代表的意義如下

綠色的部分是ground truth,如果我們預測的點剛好與之重合,那麼OKS=1,藍色圈代表着2倍標準差,此時的OKS=0.88,紅色的圈4倍標準差,此時OKS=0.61。

自頂向下

之前我們說自頂向下是先找人,再找點,那麼找人的目標框的方法如下:

  1. One Stage:  YOLO、SSD等;
  2. Two Stage: Faster RCNN,Mask RCNN等;
  3. Anchor Free: CornerNet,CenterNet;

對於自頂向下的關鍵點檢測的方法有: Mask RCNN(增加了關鍵點檢測分支後的)、AlphaPose等。

對於Mask RCNN,我們來看一下是如何進行人體關鍵點檢測的

對於Mask分支,首先我們不再進行一個80分類的預測,而是改成28*28*17的預測,這個17就是人體的關鍵點的數量,mask分支也就變成了keypoints分支。具體如下

  1. 增加keypoint head(28*28*17)
  2. 對每一個關鍵點預測一個"Heat map"
  3. 通過one-hot encoding來進行一個softmax的計算一個最有可能的空間的位置

對於feature map的熱力分佈圖(Heatmap)

這裏顯示的是該關鍵點出現在某一個區域的最大概率。越紅的地方代表概率最大,而藍色或者淺色的地方代表概率比較小。這裏有17個heatmap,就意味着有17個點,17個類。

當我們找到這些點之後,再將其連接起來就好了。

堆疊沙漏網絡(Stacked Hourglass Networks)

首先我們知道越淺層的網絡只能提取出一些圖片的淺層信息,比如顏色、紋理等等。越深層的網絡越能提取出深層信息,比如語義信息(人類能夠理解的信息,比如人臉,身體形狀等等)。

這是一個最簡單的CNN的示例圖。堆疊沙漏網絡使用了多尺度的卷積特徵,在之前的網絡中,大多使用最後一層的卷積特徵,因爲我們認爲最後一層卷積特徵會含有豐富的語義信息。但是這樣會造成信息的丟失,對於姿態估計這種任務,全身不同的關鍵點,比如手腕、鼻子等並不是在相同的feature map上有最好的識別精度。

比如說胳膊會在第二個卷積層上比較容易識別,頭部會在第四個卷積層上更容易識別。所以如果僅僅在最後一層來進行識別的話會造成信息丟失。所以這個時候需要使用可以識別多個feature map的網絡結構。

堆疊沙漏網絡特別像一個橫着的沙漏,而且它是高度對稱的。這裏的bottom-up指的是將圖片從高分辨率到低分辨率。然後相反,top-down的過程是將圖片從低分辨率上升到高分辨率。

這裏是一個堆疊沙漏網絡的一個小模塊,堆疊沙漏網路設計的初衷就是爲了捕捉每一個尺度下的信息。通常的做法就是使用多個通道(pipeline)單獨處理不同尺度下的信息,然後在網絡的最後組合這些特徵。上圖中max pooling將圖像從高分辨率降低到一個很低的分辨率,在每一個max pooling的過程當中,網絡產生的分支在提前池化的分辨率下使用更多的卷積。在達到最低分辨率的時候,採用Up Sampleing(上採樣),再同時結合不同尺度下的特徵,再進行不同特徵下的元素相加。當達到一個不錯分辨率的時候,採用兩個1*1的卷積層進行最後的預測。

上圖中的每一個卷積都使用的是殘差網絡模塊,就是右上角的模塊。

這是一個熱力圖(Heat Map),第一張圖像是輸入圖像最終預測的關鍵點圖。第二張圖是對頸部節點的概率預測,顏色越深就代表着這個地方存在概率是最大。藍色區域就代表不可能存在頸部。

在上圖中,N1代表第一個沙漏網絡,它提取出來的混合特徵會經過一個1*1的全卷積之後分成上下兩個分支,上面的分支繼續經過一個1*1的卷積,繼續進入下一個沙漏網絡。下面的分支會生成一個熱力圖(Heat Map),也就是藍色的矩形框。一般的卷積層的通道數都會比較高,比如256或者512等等,但是這個Heat Map的通道數需要跟我們預測的關鍵點的數量一致,比如說是17個,這也是這個藍色矩形框比較窄的原因。在生成了Heat Map之後依然要通過一個1*1的卷積來調整通道數,使得通道數跟上面的分支一致,方便進行後面的合併。合併之後再作爲下一個沙漏網絡的輸入。

這裏需要注意的是,一般的卷積神經網絡的損失函數只考慮最後一個卷積層的輸出與ground truth進行一個損失,但是在沙漏網絡中,由於每一個沙漏網絡都會產生一個Heat Map,故每一個沙漏網絡的loss都會放進最終的loss中進行計算,這樣比只考慮最後一個沙漏網絡的輸出精度要大。考慮這種每一步的損失叫做中間監督

上圖的這個沙漏模塊只是一個簡單的沙漏模塊,可以稱爲一階沙漏模塊。我們可以把中間虛線框不斷的替換成沙漏模塊,如下圖所示

這樣就是一個完整的沙漏模塊,稱爲四階沙漏模塊。作者其實是串聯了四個四階沙漏模塊,最後做一個輸出。

該圖是作者給出的實驗結果,我們可以看到效果還是很不錯的。他使用的是MPII的數據集。

該方法對於單個的人體姿態估計是比較好的,但是對於多人來說,不同的人的關鍵點當離的比較近的時候可能會產生干擾。

AlphaPose

AlphaPose是一個自頂向下的多人姿態估計框架,是由上海交通大學的盧策吾團隊和騰訊優圖提出的,發表於ICCV,在MPII數據集上達到76.7mAP。AlphaPose採用了當時先進的Faster RCNN作爲人體框檢測器+SPPE(single-person pose estimator)人體姿態估計模型。SPPE的原理其實就是上面說的堆疊沙漏網絡

AlphaPose拋出了兩個問題

  1. 邊界框定位錯誤
  2. 姿態冗餘

由於SPPE對人體目標框的要求非常苛刻,所以如果一旦預測的人體邊界框不準的時候就無法預測出人體的關鍵點。

上圖中,紅色的框是ground truth,黃色的框是預測的邊界框,此時黃色的框和紅色的框的IoU是大於0.5的,一般我們認爲黃色的框在對於目標檢測來說已經達到了我們的要求了。但是當我們把紅色的框和黃色的框分別裁剪送入到SPPE之後,我們會發現紅色的框的熱力圖在feature map中清晰可見,而黃色的框的熱力圖中卻沒有我們需要的關鍵點的高概率區域。

上圖中同一個人體產生了三個不同的邊界框,而每一個邊界框都經過SPPE後產生了一系列的姿態關鍵點,這就是姿態冗餘。

針對這兩個問題,AlphaPose提出了RMPE(Regional Multi-Person Pose Estimation)框架,它是一種區域多人姿態估計框架,即使在人體邊界框定位出錯的情況下也能進行正確估計,該框架包含三個部分

  1. SSTN(Symmetric Spatial Transformer Network)對稱空間變換網絡
  2. P_Pose NMS(Parametric Pose Non-Maximum-Suppression)參數化姿態非極大值抑制
  3. PGPG(Poss-Guided Proposals Generator)姿態引導區域框生成器

SSTN對稱空間變換網絡

SSTN的結構圖如上圖所示,首先輸入一張圖片,該圖片中有兩個人體,一個穿綠色衣服,一個穿黑色衣服。我們的目的是檢測穿綠色衣服的人體姿態。由圖片可知,穿綠色衣服的人體並未位於圖片中間,由於SPPE對位置錯誤非常敏感,我們需要使得穿綠色衣服的人體位於圖片的中間。我們將這幅圖片送入STN網絡(空間變換網絡),該網絡使用網格生成器和採樣器去提取一個人所在的區域,STN能很好地自動選取ROI,使用STN去提取一個高質量的人體區域框。

STN網絡包含三部分

  1. 本地網絡(Loalisation Network)
  2. 網格生成器(Grid Genator)
  3. 採樣器(Sampler)

本地網絡是一個用來回歸變換參數θ的網絡,它的輸入是特徵圖像,然後經過一系列的隱藏網絡層(全連接或者卷積網,再加一個迴歸層)輸出空間變換參數。θ的形式可以多樣,如需實現2D仿射變換,θ 就是一個6維(2x3)向量的輸出。θ的尺寸大小依賴於變換的類型。

網格生成器(Grid Generator)是依據預測的變換參數來構建一個採樣網格,它是一組輸入圖像中的點經過採樣變換後得到的輸出。網格生成器其實得到的是一種映射關係假設特徵圖像U每個像素的座標爲,V的每個像素座標爲空間變換函數爲二維仿射變換函數,那麼的對應關係可以寫爲:

採樣器利用採樣網格和輸入的特徵圖同時作爲輸入產生輸出,得到了特徵圖經過變換之後的結果。

以上是前向計算,反向傳播中,輸出對採樣器的求導公式爲:

grid generator的求導公式

import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

        self.localization = nn.Sequential(
            nn.Conv2d(1, 8, kernel_size=7),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.ReLU(True),
            nn.Conv2d(8, 10, kernel_size=5),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.ReLU(True)
        )
        self.fc_loc = nn.Sequential(
            nn.Linear(10 * 3 * 3, 32),
            nn.ReLU(True),
            nn.Linear(32, 3 * 2)
        )
        self.fc_loc[2].weight.data.zero_()
        self.fc_loc[2].bias.data.copy_(torch.tensor([1, 0, 0, 0, 1, 0], dtype=torch.float))

    def stn(self, x):
        xs = self.localization(x)
        xs = xs.view(-1, 10 * 3 * 3)
        # 經過本地網絡的卷積和全連接層得到一個θ
        theta = self.fc_loc(xs)
        theta = theta.view(-1, 2, 3)
        # 生成一個仿射變換的網格
        grid = F.affine_grid(theta, x.size())
        # 對特徵圖進行座標仿射變換
        x = F.grid_sample(x, grid)
        return x

    def forword(self, x):
        x = self.stn(x)
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

我們繼續回到SSTN,通過STN網絡的圖像變換,獲得穿綠色衣服的人體居中圖像(剪裁後的圖像),再輸入SPPE預測人體姿態。再通過SDTN(空間反變換網絡,STN結構的反向結構)反向輸入回原始圖像,將剪裁後的圖像還原至原始圖像。

在SPPE的下方還有一個Parallel SPPE,它的作用是用來優化STN。Parallel SPPE在檢測出人體姿態後,會判斷剪裁後的人體是否位於圖像中心的位置,如果不在中心就返回較大的誤差,從而自動優化STN網絡。在測試階段,Parallel SPPE不會使用,因此只有在訓練階段Parallel SPPE纔會產生作用。Parallel SPPE可以看作是訓練階段的正則化過程,有助於避免局部最優的情況(STN不能把姿態轉換到提取到人體區域框的居中位置)。但是SDTN的反向修正可以減少網絡的錯誤進而降低陷入局部最優的可能性。這些錯誤對於訓練STN是很有影響的。通過Parallel SPPE,可以提高STN將人體姿態移動到檢測框中間的能力。

儘管STN可以部分修改輸入,但是不可能完美的將人定位在標籤的位置。在座標空間上的輸入和SPPE標註的差異會很大程度的損害訓練姿態估計的能力。這會導致我們主分支SPPE的性能下降。因此,爲了確保STN和SPPE同時發揮自己的作用,一個固定權重的Parallel SPPE是不可缺少的。Parallel SPPE總是會產生較大的誤差,會將沒有中心的姿態來推動STN產生一個有中心的姿態,但是不會影響到主分支SPPE的效果。

P_Pose NMS參數化姿態非極大值抑制

P_Pose NMS有兩個標準來進行冗餘姿態消除。一個是置信度消除,一個是空間距離消除,只要滿足其中的一個標準,多餘的姿態就會被消除。我們先來看一下置信度消除。

置信度消除的原理是統計兩個姿態關節點置信度相似的總個數。Pi和Pj是估計出來的兩個人體姿態。假設Pi=0.98,Pj=0.91。首先我們需要根據置信度將這兩個姿態進行一個排序,很明顯Pi>Pj。然後我們選取Pi作爲參考姿態,以此來判斷Pj是否需要被消除。Ki、Kj是Pi、Pj的關節點座標,並且Bi是Pi的關節點Ki的熱點區域,是Pi檢測框的1/10。

此時我們需要判斷Kj是否在Bi的範圍內。如果Kj在Bi範圍內,且此時兩個關節點的置信度相似(比如說Ki的置信度Ci爲0.98,Kj的置信度Cj爲0.97),則以下函數值爲1。如果兩個關節點的置信度不相似,則該函數的值爲0.

如果關節點Kj不在Bi的範圍內,則該函數值直接爲0。因爲總共有17個關節點,則我們需要再重複16次以上的步驟,得到所有關節點的相似度的值。在對比了17個關節點之後統計相似關節點的總數,如果這個這個值大於5,則Pj就會被消除。

空間距離消除指的是計算兩個姿態關節點的空間距離總和,依然是選取置信度最高的姿態Pi作爲參考姿態,然後計算兩個姿態關節點的位置距離,如果Pj姿態離Pi姿態比較近,說明這兩個姿態的重疊度比較高,Pj就會被消除。計算公式如下

PGPG姿態引導區域框生成器

對於Alphapose,適當的數據增強有助於訓練SSTN+SPPE模塊,一種增強方法是在訓練階段使用檢測出來的人體檢測框,但是由於在進行目標檢測只能生成一個人體檢測框,所以STN+SPPE模塊得不到充分訓練,因此需要PGPG進行數據增強。

不同姿態的偏移量分佈是不同的,P(δB|atom(P))表示原子姿態P的偏移量分佈,atom(P)是原子姿態(代表一個種類的姿態,通過聚類獲得,比如站、躺等姿態)。

P(δB|atom(P))

計算每個原子姿態邊界框的偏移量,將真實邊框的邊長進行歸一化處理後,偏移量會形成一個頻率分佈,將頻率分佈擬合成高斯混合分佈。可以得到不同原子姿態的高斯混合分佈,如上圖所示。根據這些高斯分佈,可以生成大量的預測框,就可以訓練sstn模塊。這就是數據增強PGPG的原理和過程。

自底向上

OpenPose

OpenPose是一個自底向上的多人體姿態估計框架,是美國卡耐基梅隆大學(CMU)基於卷積神經網絡和監督學習並以caffe爲框架開發的開源庫。自底向上的人體姿態估計並不會先去識別一個人體,而是先找人體的關鍵點。

輸入作爲一張圖像,然後它會有兩個分支。一個是部分置信度圖(Part Confidence Maps),一個是部分向量場圖(Part Affinity Fields)。部分置信度圖是爲了找關鍵點熱力圖,部分向量場圖是爲了找這些關鍵點之間的聯繫,或者是人體的連接關係,四肢走向。通過這兩個分支既找到了關鍵點,又找到了關鍵點的聯繫,然後再進行細微的優化調整,最後把屬於同一個人的關鍵點歸納到一起之後再進行連線。

無論是自頂向下還是自底向上,第一步都一定是找特徵,我們可以通過主幹網絡來獲取,主幹網絡可以是VGG、ResNet、DenseNet、DarkNet、CSP、FPN、PAN或者是之前說的沙漏網絡。獲取了feature map之後,第二步開始分枝,進行多任務網絡,上面的分支就是找關鍵點的熱力圖,下面的分支就是找關鍵點之間的聯繫。如果一張圖片中只有單獨的一個人,此時就非常簡單。但是如果存在多人,或者是多人重疊遮擋,有些不同的人的關鍵點離的非常近,或者是彼此有遮擋。如果在自頂向下的時候會有一個誤判,但是在自底向上的方向,它有第二條支路,找關鍵點之間的聯繫,如果不同的關鍵點屬於同一個人的話,它們的連線應該落在同一個人身上。所以第二條支路的意義就是區分不同的關鍵點是否屬於同一個人。

上圖中,圖片輸入通過主幹網絡(這裏是VGG19),得到預測人體關鍵點位置的Condifence Maps(置信度圖,其實就是熱力圖)。

同時,feature map通過第二個分支,得到了Part Aaffinities(向量場圖)。我們來看一下在訓練過程中,是如何來找一個關鍵點的,我們以找一個運動員右手腕關鍵點爲例。

上圖中,將圖像送入卷積網絡。實際上,我們要找的是右手腕,但是在經過第一個Stage我們看到在第二幅熱力圖中,運動員的左手腕有明顯的熱力圖點,而右手腕附近卻只有零散的淡綠色圖。這是找錯了,需要修正,經過第二個Stage後,熱力圖點集中在右手腕附近,而左手腕附近還有零散的淡綠色。此時需要進一步修正,在經過第三個Stage後,我們看到所有的熱力圖點只有右手腕有了,其他地方都消失了。但是我們需要注意的是,熱力圖的feature map的通道數與關鍵點的數量是一致的,所以我們要尋找的17個關鍵點其實是同時尋找的,只不過分佈在不同通道的feature map上。如下圖所示

它是在feature map的不同通道上分別尋找鼻子、脖子、右肩、右肘、右手腕等。這是一個最終的效果圖。

上圖是一個一般性的步驟,第一步得到所有人的所有關鍵點,第二步是將屬於同一個人的關鍵點給連接起來。但是該如何連接,其實並沒有那麼簡單。

這裏我們以左肘部和左手腕爲例來說明,其實一開始我們會將所有的關鍵點都連接起來,不管它們到底是不是同一個人的,之後經過訓練和ground truth的比對,會獲得連接正確和錯誤的概率,通過上圖,我們知道連接正確的概率爲1,而連接錯誤的概率會很小,以此來去掉連接錯誤的連線,留下正確的連線。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章