ST-GCN 實現人體姿態行為分類
引用
人體行為識別是計算機視覺及機器學習方面的熱門研究領域。它在對視頻中的人類行為進行運動分析、行為識別乃至延伸至人機交互領域都有著非常廣泛的應用。研究初期,人體行為識別主要是以基于靜態圖像為研究對象。通過提取靜態圖像中的人體動作特征并對動作進行分類。然而僅基于靜態圖像來進行識別人體行為的局限性在于人體行為是連續、動態的,單憑一張靜態圖像無法進行判斷識別。而基于視頻為研究對象,可以將視頻看作連續靜態圖像的時間序列。近兩年,很多基于視頻為對象的人體行為識別取得了不錯的成果,例如,Gao等人以多視角的視頻為基礎開發出了一種自適應融合和類別級詞典學習模型。
在通常情況下,人體行為識別有著例如外觀、光流、身體骨骼和深度等多種模態,人們可以通過這些模態建模并傳達重要信息進而實現人體行為識別。近幾年,比較熱門的深度領域有著很多的成果,Kamel等人利用使用卷積神經網絡從深度圖和姿勢數據中進行人體行為識別。Ji等人利用深度圖來將骨骼信息嵌入從而達到對人體進行分區的目的,以及Zhao等人提出了一種貝葉斯分層動態模型用于人類動作識別也取得了不錯的效果。而在這些模態當中,人類身體骨骼通常能與其他模態相輔相成并傳達重要信息。同時也因為骨骼信息的清晰直觀且不易受到人體外觀等其他因素的影響,具有良好的魯棒性。
基于骨架的人體行為識別方法因對復雜場景具有較強的魯棒性,因此近些年涌現很多基于骨架的動作識別方法。一般分為兩種方法:
(1)基于人工特征選擇的方法,通過人工設定的特性來捕捉關節運動動態。例如關節的相對位置、關節軌跡的協方差矩陣或是身體部分之間的平移旋轉等特性。
(2)深度學習方法,基于深度學習進行骨架建模,端到端的動作識別模型通過使用遞歸神經網絡和臨時CNNs來學習。ST-GCN不同于這些方法,雖然強調了人體關節建模的重要性,但這些部分一般使用領域知識明確分配指定。ST-GCN將GCN應用于基于骨架的人體行為識別系統中,在此基礎上加入了對識別人體行為非常重要的關節之間的空間關系這一因素,以人體關節為節點,同時連接關節之間的自然聯系和相同關節的跨連續時間聯系,然后以此為基礎構造多個時空圖卷積層,沿時空維度進行集成信息。
故本項目通過搭建ST-GCN實現對視頻時空流進行姿態估計和行為分類。最終可實現效果如下:
1、ST-GCN 介紹
ST-GCN是香港中文大學提出一種時空圖卷積網絡,可以用它進行人類行為識別。這種算法基于人類關節位置的時間序列表示而對動態骨骼建模,并將圖卷積擴展為時空圖卷積網絡而捕捉這種時空的變化關系。
1.1 模型通道
基于骨架的數據可以從動作捕捉設備中獲得,也可以從視頻中獲得姿態估計算法。通常數據是一個坐標系序列,每個坐標系都有一組關節坐標。ST-GCN就是構建一個以關節為圖節點,以人體結構和時間為圖邊的自然連接為圖節點的時空圖。ST-GCN的輸入是圖節點上的關節坐標向量。這可以看作是對基于圖像的cnn的模擬,其中輸入是由駐留在2D圖像網格上的像素強度向量構成的。對輸入數據進行多層次的時空圖卷積運算,在圖上生成更高層次的特征圖。然后它將被標準的SoftMax分類器分類到相應的動作類別。
1.2 骨骼圖結構
骨骼序列通常由每一幀中每個人體關節的2D或3D坐標表示。使用卷積進行骨骼動作識別,將所有關節的坐標向量連接起來,形成每幀的單一特征向量。
1.3 時空模型
針對空間時間建模。在構建了空間圖之后,需要在骨骼序列中建模時空動態。在構建圖的時候,圖的時間方面是通過在連續的框架中連接相同的關節來構建的。從而能夠定義一個非常簡單的策略,將空間圖CNN擴展到空間時域。
2、模型實驗
2.1 環境搭建
1、首先下載好完整無誤配置好的代碼(包括模型等等,見文末)。
2、搭建最新版的openpose環境,并使用cmake編譯。
3、配置好python的cuda環境,以及opencv等基礎環境。
4、使用命令
“python main.py demo --openpose E:/cmake/environment/x64/Release --video 2.mp4”進行測試生成結果。
其中“E:/cmake/environment/x64/Release”需要改成自己的openpose環境。
2.2 主函數調用
其中主函數通過使用processors管理的設定好的分類識別、輸入輸出管理等程序內部函數進行整個程序的布置。
代碼如下:
import argparse import sys import torchlight from torchlight import import_class if __name__ == '__main__': parser = argparse.ArgumentParser(description='Processor collection') processors = dict() processors['recognition'] = import_class('processor.recognition.REC_Processor') processors['demo'] = import_class('processor.demo.Demo') subparsers = parser.add_subparsers(dest='processor') for k, p in processors.items(): subparsers.add_parser(k, parents=[p.get_parser()]) arg = parser.parse_args() Processor = processors[arg.processor] p = Processor(sys.argv[2:]) p.start()
2.3 模型網絡
通過調用空間-時間圖卷積網絡建立這個網絡模型。其中參數in_channels (int)為輸入數據中的通道數;
num_class (int)表示用于分類任務的類的數量;
graph_args (dict)表示構建圖的參數;
edge_importance_weighting (bool)表示如果“True”,添加一個可學習的對圖的邊進行重要性加權。代碼如下:
def __init__(self, in_channels, num_class, graph_args, edge_importance_weighting, **kwargs): super().__init__() self.graph = Graph(**graph_args) A = torch.tensor(self.graph.A, dtype=torch.float32, requires_grad=False) self.register_buffer('A', A) spatial_kernel_size = A.size(0) temporal_kernel_size = 9 kernel_size = (temporal_kernel_size, spatial_kernel_size) self.data_bn = nn.BatchNorm1d(in_channels * A.size(1)) kwargs0 = {k: v for k, v in kwargs.items() if k != 'dropout'} self.st_gcn_networks = nn.ModuleList(( st_gcn(in_channels, 64, kernel_size, 1, residual=False, **kwargs0), st_gcn(64, 64, kernel_size, 1, **kwargs), st_gcn(64, 64, kernel_size, 1, **kwargs), st_gcn(64, 64, kernel_size, 1, **kwargs), st_gcn(64, 128, kernel_size, 2, **kwargs), st_gcn(128, 128, kernel_size, 1, **kwargs), st_gcn(128, 128, kernel_size, 1, **kwargs), st_gcn(128, 256, kernel_size, 2, **kwargs), st_gcn(256, 256, kernel_size, 1, **kwargs), st_gcn(256, 256, kernel_size, 1, **kwargs), ))
2.4 ST-GCN網絡建立
建立ST-GCN網絡模型,其中in_channels (int)表示輸入序列數據中的通道數;
out_channels (int)表示卷積產生的通道數;
kernel_size (tuple)為時態卷積核和圖卷積核的大小;
stride (int,可選)為時間卷積的步幅。默認值:1;
dropout (int,可選)為最終輸出的輟學率。默認值:0;
residual (bool,可選)表示如果”True “,應用殘留機制。默認值:“True”。
代碼如下:
def __init__(self, in_channels, out_channels, kernel_size, stride=1, dropout=0, residual=True): super().__init__() assert len(kernel_size) == 2 assert kernel_size[0] % 2 == 1 padding = ((kernel_size[0] - 1) // 2, 0) self.gcn = ConvTemporalGraphical(in_channels, out_channels, kernel_size[1]) self.tcn = nn.Sequential( nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d( out_channels, out_channels, (kernel_size[0], 1), (stride, 1), padding, ), nn.BatchNorm2d(out_channels), nn.Dropout(dropout, inplace=True), ) if not residual: self.residual = lambda x: 0 elif (in_channels == out_channels) and (stride == 1): self.residual = lambda x: x
運行過程如下可見,在這里通過雙擊“test.bat”即可直接運行:
完整代碼:
鏈接:
https://pan.baidu.com/s/1Ht7Mr6hJMt5oUKu6ue05fw
提取碼:0nqh
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。