論文まとめ：Coarse-to-Fine Volumetric Prediction for Single-Image 3D Human Pose

# はじめに 
CVPR2017 から以下の論文
[1] G. Pavlakos, et. al."Coarse-to-Fine Volumetric Prediction for Single-Image 3D Human Pose", CVPR2017.
のまとめ


● 著者らのプロジェクトページ
https://www.seas.upenn.edu/~pavlakos/projects/volumetric/


● arXiv:
https://arxiv.org/abs/1611.07828


● 既にいくつかまとめ記事が存在する。
１）yusuke ujitoko 氏のブログ：
http://yusuke-ujitoko.hatenablog.com/entry/2017/08/06/015654

２）DeNA naoki kato 氏のまとめ：
https://engineer.dena.jp/2019/12/cv-papers-19-3d-human-pose-estimation.html


● コード
１）著者らの matlabでの実装
https://github.com/geopavlakos/c2f-vol-demo

２）その他有志の caffe での実装
https://github.com/strawberryfg/c2f-3dhm-human-caffe


# 概要 
1. 単眼カメラから３次元の姿勢を推定するモデル
2. 関節の heat map を３次元的に推定する
3. hourglass なネットワークを複数回繰り返すことで深さ方向の推定精度を増していく

２に関しては以下の図のような Volumetric な heat map を出力する。

<img width="429" alt="CtoF_3Dpose_img00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/c978c575-a991-80ca-57ca-ae1009bffc10.png">


# ３次元 heat map 
３次元 heat map は２次元 heat mapを３次元に拡張したもので、図にするとこんな感じか？

<img width="681" alt="CtoF_3DPose_img20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/1f9ca041-0398-7deb-824c-07f535c02766.png">

２次元 heat map と同様に関節点に対してガウシアンをかけ、生成する。関節点を $(i,j,k)$ とすると、$(x,y,z)$ における heat map の値は

```math
G_{i,j,k}({\bf{x}}^n_{gt}) = \frac{1}{2 \pi \sigma^2} \exp \left[ - \frac{(x-i)^2 + (y-j)^2 + (z - k) ^2}{2 \sigma^2} \right]
```

となる。よくある heat map と違って基準化定数があるが、 $\sigma = 2$ を使用するので、山のピークはそれほど低くならないだろう。

loss は MSE。

```math
\mathcal{L} = \sum^N_{n=1} \sum_{i,j,k} \| G_{(i,j,k)} ({\bf{x}}^n_{gt}) - p^n_{(i,j,k)}  \|^2
```

$n$ は関節の番号。

# Carse-to-fine prediction 
OpenPose 等で用いられている「モジュールを多段に経てだんだん正確なheatmapにする仕組み」に近いが、幾つかの点で異なる。

<img width="842" alt="CtoF_3Dpose_img01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/cc427cf0-b617-545b-dfb9-0da5f40c0dd6.png">

### 1. 深さ方向を少しずつ増やす

違いの１つ目は、ステージを経るごとに深さ方向を増やすしくみ。

voxel なので、中間層における heatmapの要素数をできるだけ減らしたい。そこでステージ１では深さの要素数１、ステージ２では２、ステージ３では４、と $2^n$ で増やしていく。

### 2. 中間層の heat map を分離する
以下の図で
<img width="431" alt="CtoF_3Dpose_img02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/ed18514c-a9d8-1632-09aa-7612ed9fa88a.png">
(a)では prediction の一部であるあるステージの heatmap に対し、そのまま次のステージの入力として利用している。

これだと特にステージ１においては深さ方向が１、つまり2Dの画像になるが、その情報のみから次のステージで深さ方向を復元することになってしまう。これは困難だろう。

そこで(b)のように深さ情報も含めた特徴量とheatmapとを分け、その後両者をconcate（？）して次のステージに伝える。

# 実験と結果
### 1. ３次元 heat map の効果

<img width="430" alt="CtoF_3Dpose_img03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/39335f6c-31d9-7258-775b-26e4879300c6.png">

各関節の座標を回帰問題として解いた場合と３次元 heat map を用いた場合との mean per joint error の比較。

３次元 heat map の方がよい。

### 2. 多ステージなアーキテクチャの効果 
<img width="422" alt="CtoF_3Dpose_img04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/558a1779-52b8-116f-e123-98ac289270ac.png">
例えば、左側が L1:64 depth, L2:64 depth と常に64 の深さのheat mapを出力する場合と、その右側 L1:1 depth, L2:64 depth と最初は小さく、その後大きくする場合とを比較した場合、後者の方が mean per joint error は低くなっている。

中間層のfeature map 、あるいはその周囲のパラメータは減っているはずだが、逆に性能がよくなっていて、興味深い。

### 3. 他モデルとの比較 
<img width="434" alt="CtoF_3Dpose_img06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/4571c9a5-db9b-3502-3398-b31b5d5ac983.png">
Human 3.6M dataset でたモデルとの比較をした場合、 reconstruction error はかなり小さくなっている。<font color="red">なぜメトリクスを変えた？</font>

### 4. 定性的評価 
<img width="903" alt="CtoF_3Dpose_img10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/33f4c213-df4f-d036-175d-61216d410792.png">

左側入力画像に対し、その右２つが prediction。predictionの左は入力画像と同じ角度から見た3d poseで、その右はそれを回転させたもの。