【論文筆記+復現踩坑】End-to-end Recovery of Human Shape and Pose(CVPR 2018)


PS. 這里做的論文筆記主要是為自己方便回顧。

概述

做了什么:引入一個端到端的Human Mesh Recovery框架,從包含人體的RGB位圖中重建出一個SMPL的3D網格,並嘗試重新投影回圖片上

目的:最小化關鍵點的重投影損失,使得我們可以使用只帶2D准確標注的戶外場景圖像就能進行訓練

難點:

  • 缺乏自然場景下的大規模ground truth的3D數據集
  • 單視角下2D到3D映射所固有的模糊性(缺乏深度信息),可能會導致產生的模型異常,如自相交、異常的人體姿勢等情況
  • 預測相機視角又會在人體大小和攝像機的距離建引入額外的scale ambiguity
  • 旋轉的回歸問題

關鍵點:

  • 在從圖片推斷出3D人體模型后,將它重投影到2D圖片上計算2D損失
  • 引入生成對抗網絡(GANs),通過訓練鑒別器來推斷生成的3D人體模型是否為真人,且形體姿勢是否合理(需要3D訓練集)(鑒別器能夠學到3D關節角度的限制)
  • 由於歐拉角旋轉表示法存在多對一的映射,轉換成旋轉矩陣可以保證其唯一性

優點:

  • 直接從圖像推斷出SMPL參數
  • 可以直接生成網格
  • 方法是端到端的
  • 可以不需要使用配對的2D-3D數據集,並且不依賴中間2D關鍵點偵測
  • 運行效率可以達到實時級別(1080Ti在部件分割任務上用時0.04sec)

現有的一些從2D圖片恢復人體3D網格的方法專注於恢復人體3D關節點的坐標位置。但問題在於:

  • 關節點是離散的,但人體在3D空間的表示是密集連續的
  • 3D關節點位置本身並不能約束每個關鍵點之間的關系,僅通過這些位置並不能很好的預測人體姿勢和體型

論文的做法:

  • 為kinematic tree中的每個3D關鍵點輸出相對的3D旋轉矩陣,來捕獲3D的頭部和肢體角度方向。預測角度還可以確定肢體的對稱性和肢體長度等信息的合理性
  • 該模型從3D人體模型數據集中能夠學習到3D關節角度的限制

論文具體做法

數據集輸入:帶2D關節點Ground Truth的圖像數據

Encoder

使用ResNet-50網絡對圖像進行編碼

  • Input:224x224 RGB圖像
  • Output:經過平均池化后的特征\(\phi\in\mathbf{R}^{2048}\)

3D Regression

  • Input:concat后的\([\phi, \Theta_t]\),初始的\(\Theta_0\)源自neutral_smpl_mean_param.h5

  • Layer 1:Linear(2048 + 85, 1024), ReLU(), Dropout(0.5)

  • Layer 2:Linear(1024, 1024), ReLU(), Dropout(0.5)

  • Layer 3:Linear(1024, 85)

  • Output:\(\Delta\Theta_t\)

Iterative error feedback(IEF):計算出殘差\(\Delta\Theta_t\)后進行加法更新:\(\Theta_{t+1}=\Theta_{t} + \Delta\Theta_t\)

其中\(\Theta=\{\mathbf{\theta}, \mathbf{\beta}, R, t, s\}, \mathbf{\theta}\in\mathbf{R}^{3K}, \mathbf{\beta}\in\mathbf{R}^{10},R\in\mathbf{R}^{3},t\in\mathbf{R}^{2},s\in\mathbf{R}\).K=23,θ為SMPL關節點的軸角,β控制SMPL體型,R為全局軸角,t為攝像機xy平面的平移量,s為攝像機的縮放量

\(M(\mathbf{\theta}, \mathbf{\beta})\):代表SMPL模型的N=69803D頂點

\(X(\mathbf{\theta}, \mathbf{\beta})\):代表SMPL模型的23個3D關節點

對3D關節點的投影\(\hat{\mathbf{x}}=s\Pi(RX(\mathbf{\theta}, \mathbf{\beta})) + t\)\(\Pi\)為正交投影

損失函數

如果有3D ground truth,則對應的annotation為\([\mathbf{\beta}, \mathbf{\theta}]\)。網絡輸出則為\([\hat{\mathbf{\beta}}, \hat{\mathbf{\theta}}]\)

  • 2D Loss:\(L_{reproj}=\sum_i\parallel v_i(\mathbf{x}_i - \hat{\mathbf{x}}_i)\parallel_{1}\)\(v_i\)為2D關節點i的可視性(1可見,0不可見)
  • 3D SMPL Loss:\(L_{smpl}=\parallel[\mathbf{\beta_i}, \mathbf{\theta_i}] - [\hat{\mathbf{\beta_i}}, \hat{\mathbf{\theta_i}}]\parallel_2^2\)
  • 3D Joint Loss:\(L_{joints}=\parallel(\mathbf{X}_i - \hat{\mathbf{X}}_i)\parallel_2^2\)
  • 3D Loss:\(L_{3D}=L_{smpl}+L_{joints}\)

Discriminator

  • Input:\(\beta, \theta\)

Shape Discriminator:

  • Layer 1:Linear(10, 5), ReLU()
  • Layer 2:Linear(5, 1)

Pose Discriminator(C=9是因為軸角變成旋轉矩陣):

  • Input:NHWC = [N, 23, 1, 9]

  • Layer 1:Conv2d(out_c=32, k=1x1), ReLU()

  • Layer 2:Conv2d(out_c=32, k=1x1), ReLU()

    For pose respectively(K):

    • Layer 3:[N, 1, 1, 32]---Fully Connected--->Linear(32, 1)--->[N, 1]

    For all pose(1):

    • Layer 3:[N, 23, 1, 32]=FC1024, ReLU() =>[N, 1024]
    • Layer 4:FC1024, ReLU()
    • Layer 5:FC1

Total:K+2 Discriminator

損失函數:

  • Adversarial Loss for the encoder:\(min L_{adv}(E)=\sum_i\mathbf{E_{\Theta\sim p_E}[(D_i(E(I))-1)^2]}\)
  • Objective for each discriminator:\(min L(D_i)=\sum_{i}\mathbf{E_{\Theta\sim p_{data}}}[(D_i(\Theta)-1)^2] + \mathbf{E_{\Theta\sim p_E}}[D_i(E(I))^2]\)
  • Objective for encoder:\(L=\lambda(L_{reproj}+\mathbf{1}\ L_{3D})+L_{adv}\),這里1代表是否有ground truth 3D數據

實驗

評價指標:

  • Reconstruction: mean per joint position error(MPJPE) 、 Reconstruction error、PCK、AUC
  • Part segmentation: Acc、F1-score

測試數據集:Human3.6M,MPI-INF-3DHP

實驗方法:

  • T1、T2:對Human3.6M用不同方法評估Reconst. Error
  • T3:對MPI-INF-3DHP,控制剛體對齊
  • T4:部件分割
  • Fig:對比使用/不使用配對的2D-to-3D監督

復現Demo踩坑

踩這個項目的坑踩了我好久,這里把環境配置的過程簡單整理下。

復現主要環境:

  • Linux Ubuntu 18.04
  • Anaconda3
  • Python2.7

先按順序安裝下面這些包:

版本 安裝源
cudatoolkit 9.0 conda
cudnn 7.6.5 conda
numpy 1.14.0 pip
tensorflow-gpu 1.12.0 pip

numpy的版本不要太新,不然后續編譯使用opencv2可能會帶來一系列麻煩。

tensorflow-gpu使用的是項目推薦的版本

然后用下面的代碼測試即可,得到True為成功:

import tensorflow as tf
print(tf.test.is_gpu_available())

編譯安裝opencv2

為了使用cmake編譯opencv2,這里需要先安裝一些東西:

$ sudo apt-get install build-essential
$ sudo apt-get install cmake
$ sudo apt-get install pkg-config

因為我們用的是python2.7,pip提供的opencv-python主要都是給python3.x用的,為此我們需要自己編譯一個。

這里我選擇的是opencv-2.4.13.6的版本:https://gitee.com/dhfhub/opencv/tree/2.4.13.6/

下載zip后解壓,終端跳到目錄opencv-2.4.13.6內,新建文件夾並進入,運行cmake。注意一定要是在hmr的虛擬環境下進行:

$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ../opencv

生成完畢后,開始安裝:

$ sudo make install

安裝完畢后運行python測試opencv2,此時應該沒有問題:

$ python
>>> import cv2

安裝剩余包

為了編譯安裝opendr,需要先運行下面命令安裝:

$ sudo apt install libosmesa6-dev
$ sudo apt-get install build-essential
$ sudo apt-get install libgl1-mesa-dev
$ sudo apt-get install libglu1-mesa-dev
$ sudo apt-get install freeglut3-dev

最后根據hmr項目里的requirements.txt來完成剩余安裝:

版本 安裝源
scipy 1.2.3(默認最新) pip
opendr 0.78(默認最新,不能是0.77) pip
matplotlib 2.2.5(默認最新) pip
scikit-image 0.14.5(默認最新) pip
deepdish 0.3.6(默認最新) pip
absl-py 0.10.0(默認最新) pip
ipdb 0.13.4(默認最新) pip
tensorflow-estimator 1.10.12(降級避免出現ts.estimator找不到問題) pip

嘗試運行

回到hmr項目的目錄,執行:

$ wget https://people.eecs.berkeley.edu/~kanazawa/cachedir/hmr/models.tar.gz && tar -xf models.tar.gz

獲取模型文件后解壓到hmr文件夾內,得到models的文件夾

然后嘗試執行:

$ python -m demo --img_path data/coco1.png

此時可能還有一個報錯:

TypeError: load() got an unexpected keyword argument 'encoding'
python-BaseException

Process finished with exit code 1

找到src/tf_smpl/batch_smpl.py,將dd = pickle.load(f, encoding="latin-1")里的encoding部分刪掉,然后再嘗試再次執行。這時候應該能跑出結果了。

執行:

$ python -m demo --img_path data/im1954.jpg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM