ステータス:ドラフト(2026-10-13)。 論文の数値は原典を開き、条件とともに確認しました。実際に検証した環境はノートPCのCPUによるnumpyのサンプル(
code/07_heatmap_decode.py、10秒前後)です。TT Scoreで姿勢モデルを実際に使用した結果は、TT Scoreモデル解剖編4の実測を引用しています。 シリーズ「ビジョンモデルを読む 2」第7回。次の記事: 人の姿勢 2. HRNetの構造(複数の解像度を最後まで並行して維持する点)自体は ビジョンモデルを読む 1で扱っています。本記事は「関節をどのように学習させ、取り出すか」に焦点を当てます。
人の姿勢 1: ヒートマップで関節を探す
目次
- 1. 直感:座標の代わりにマップ
- 2. 概要図:複数の人を扱う2つのアプローチ
- 3. OpenPose:四肢の方向をマップとして描く
- 4. 学習方法:ガウス正解とOKS
- 5. 実践:ヒートマップから座標を取り出す
- 6. 論文の数値
- 7. 限界
- 8. 我々のプロジェクトとのつながり
- 参考文献
1. 直感:座標の代わりにマップ
姿勢推定(pose estimation)とは、画像中の人の関節(鼻、肩、ひじ、手首、腰、ひざ、足首など)の位置を見つけるタスクです。COCOデータセットを基準に、1人あたり17点となります。
最もストレートな方法は、ネットワークに34個の座標(17点 × x, y)を直接出力させることです。2014年のDeepPoseがこれを行いました。人物のバウンディングボックスで正規化した座標を二乗誤差で回帰し、予測の周囲を切り抜いてもう一度修正するステージを設けていました(論文)。
同年、トンプソン(Tompson)らは別のアプローチを提案しました。関節ごとに 図のような形状のマップ(ヒートマップ) を出力させ、正解データも関節の位置に小さなガウス分布の山を描いたマップを作成して、ピクセルごとに二乗誤差で比較しました。そして、座標を直接回帰する方式は高精度な領域において弱いと指摘しました(論文)。それから10年近く、姿勢推定の基本はヒートマップとなりました。
ヒートマップが強力な理由は、TT Scoreモデル解剖編2でボールの検出について説明した内容と同じです。ピクセルごとに学習シグナルが生まれ、「ここではない」ということが自然に表現でき、候補が複数あっても問題ありません。人の姿勢においてはもう一つの利点があります。畳み込みは画像内の位置関係をそのまま維持するため、 位置を位置として出力する表現がネットワークの構造とよく合致するからです。
2. 概要図:複数の人を扱う2つのアプローチ
画面に複数の人がいる場合、もう一つの問題が生じます。「この手首は誰のものか。」
- トップダウン(top-down): 人物検出器でバウンディングボックスを先に見つけ、ボックスごとに切り抜いて拡大し、 1人用の 姿勢モデルに入力します。小さく写っている人でも拡大して見るため正確です。その代わり、処理時間が人数に比例し、検出器が逃した人は復元できません。
- ボトムアップ(bottom-up): 画像全体のすべての関節のヒートマップを一度に描き、関節同士を人物ごとに まとめる手がかりを同時に出力します。ネットワークを1回しか実行しないため、人数が多くても処理時間はほぼ同じです。その代わり、グルーピングの段階で間違いが起こる可能性があり、小さな人に対して弱いという欠点があります。
3. OpenPose:四肢の方向をマップとして描く
OpenPose(Caoら、CVPR 2017)におけるグルーピングの手がかりが PAF(Part Affinity Field、部位親和性場) です。前腕などの四肢ごとに2チャンネルのマップを1つ描きます。前腕の 上にある ピクセルには「ひじから手首の方向」の単位ベクトルを、それ以外のピクセルには0を代入します。人が重なっている場合はベクトルを平均します。
推論時には次のようにグループ化します。
- 関節ヒートマップのピークから、ひじの候補と手首の候補を抽出します。
- ひじの候補と手首の候補を結ぶ線分ごとに、線分に沿って「PAFベクトル · 線分方向」を積分してスコアを算出します。同じ人の腕であれば、PAFが線分と同じ方向を向くためスコアが高くなります。
- 全体を一度に解くことは非常に難しいため(NP困難)、四肢ごとに分けて 二部マッチング(ハンガリアンアルゴリズム)で解き、繋ぎ合わせます(論文)。
学習はシンプルです。関節ヒートマップとPAFの2つのブランチを複数のステージにわたって繰り返し出力させ、 ステージごとに 正解マップとの二乗誤差をとります(中間監督)。ラベルのない人が存在する領域は損失計算から除外します。ラベルがないからといって「関節がない」と教え込んではいけないからです。
速度に関する話も興味深いものです。19人が映る動画においてノートPC用GPUで8.8fpsであり(368×654入力)、9人の場合はグルーピング処理が0.58ms、ネットワークが99.6msでした(論文)。 ネットワークは1回だけで、グルーピングは非常に軽量であるというボトムアップの利点が数値として現れています。
4. 学習方法:ガウス正解とOKS
トップダウンの標準型:SimpleBaselineとHRNet
SimpleBaseline(2018)はその名の通りシンプルです。ResNetの後に逆畳み込み(deconvolution)層を3つ追加し、入力256×192から64×48のヒートマップ(¼解像度)を出力します。HRNet(2019)は、解像度を縮小してから拡大する代わりに、高解像度のブランチを最後まで維持しつつ、複数の解像度のブランチを相互に結合し続けます(構造についてはシリーズ1を参照)。
学習方法はどちらも同じです。
정답 히트맵 Hⱼ(p) = exp(−‖p − 관절 j 의 위치‖² / (2σ²)) (히트맵 칸 단위)
L = Σⱼ Σ_p (예측 Ĥⱼ(p) − Hⱼ(p))² (화소마다 제곱 오차)
HRNetの論文本文ではσを1ピクセルと記載しています(公式コードの設定値は確認していません)。データ拡張は、回転、0.65〜1.35倍のスケール変更、左右反転(左右の関節ラベルも入れ替える必要があります)、上半身・下半身のみの切り出しでした(論文)。
評価:OKSとAP
姿勢推定では「正解/不正解」を判定する基準が必要です。COCOでは OKS(Object Keypoint Similarity) を使用します。
OKS = 관절들에 대한 평균 exp( −d² / (2 · s² · (2σᵢ)²) )
d = 예측과 정답의 거리, s² = 사람의 면적, σᵢ = 관절마다 정한 상수
σᵢ は、人々がその関節をどれくらい一貫してアノテーションしているかに基づいて定められた値です。手首(0.062)のように位置が明確な関節は小さく、腰(0.107)のように服に隠れて曖昧な関節は大きくなります。同じ距離の誤差であっても、手首のほうがより厳しく減点されます。APは、OKSの閾値を0.50から0.95まで変化させながら測定した平均精度をさらに平均したものです。
5. 実践:ヒートマップから座標を取り出す
ヒートマップを¼解像度で描く場合、1グリッドは入力画像の4ピクセルに相当します。最も明るいグリッド(argmax)を選ぶだけでも、それだけで最大2ピクセル強の誤差が生じます。これを軽減するための一般的な手法が2つあります。
- ¼ピクセルシフト: 最も明るいグリッドから、2番目に明るい隣接グリッドの方向へ0.25グリッド分移動させます。SimpleBaselineやHRNetはこの手法を用います(論文)。
- DARK(2020): 予測ヒートマップをガウス分布で一度滑らかにした後、対数値のピーク周辺で2次テイラー展開を行い、ピーク位置を小数点で求めます。ガウス分布の対数は2次式になるため、この計算がうまく適合します。正解データを作成する際にも、関節の小数点位置にガウス分布の山を描くべきである(量子化してはならない)と同時に提案されました。
code/07_heatmap_decode.py を用いて3つの手法を比較しました。真の位置を小数点までランダムに3,000個置き、その位置にガウス分布を描いた完璧な予測と、ノイズ(標準偏差0.05)を混ぜた予測をデコードしました(入力ピクセル単位の平均誤差、 code/07_heatmap_decode.out.txt).
| ヒートマップ(グリッド = 入力の何ピクセルか) | σ | ノイズ | argmax | ¼ピクセルシフト | DARK |
|---|---|---|---|---|---|
| 64×48(4ピクセル) | 1 | なし | 1.52 | 0.76 | 0.00 |
| 64×48(4ピクセル) | 1 | 0.05 | 1.58 | 0.85 | 0.20 |
| 64×48(4ピクセル) | 2 | 0.05 | 1.97 | 1.29 | 0.21 |
| 32×24(8ピクセル) | 1 | 0.05 | 3.16 | 1.67 | 0.41 |
| 32×24(8ピクセル) | 2 | 0.05 | 4.03 | 2.64 | 0.41 |
同じヒートマップであっても、 デコーディングを変更するだけで誤差が1.5ピクセルから0.2ピクセルまで 変動します。グリッドが粗いほど(8ピクセル)その差はより大きくなります。DARKの0.00は完全なガウス分布であるためテイラー展開が正確に一致するためであり、実際のネットワークの出力はガウス分布ではないため、ここまで完璧にはなりません。
この誤差がスコアにどれほど影響するかをOKSに換算して検証しました(人物の面積は256×192のボックスの半分と仮定)。
오차 2화소: 손목 0.995 · 엉덩이 0.998
오차 4화소: 손목 0.979 · 엉덩이 0.993
오차 8화소: 손목 0.919 · 엉덩이 0.972
OKS 0.95の閾値(APの中で最も厳しい条件)では、手首の誤差4ピクセルと8ピクセルとで「正解」と「不正解」が分かれます。数ピクセルのデコーディングの差がAPの数値の差として現れる理由はここにあります。
6. 論文の数値
すべてCOCOの17関節、OKSベースのAPです。トップダウン方式は人物のバウンディングボックスの品質によって結果が変動するため、検出器のAPも併記しています。
| モデル | AP | 条件(論文) |
|---|---|---|
| OpenPose(bottom-up) | test-dev 61.8、ジャーナル版 64.2 | 2016年COCOコンペティション。中サイズの人物においてトップダウンより劣る |
| Associative Embedding(bottom-up) | test-dev 65.5 | 関節ごとに「誰のものか」を表すタグ値を同時に出力、マルチスケール評価 |
| SimpleBaseline ResNet-152 | test-dev 73.7 | 384×288、人物検出器AP 60.9 |
| HRNet-W32 / W48 | val 74.4 / 76.3 | 256×192 / 384×288。W32をImageNetの事前学習なしで学習した場合は73.4 |
| HRNet-W48 | test-dev 75.5、外部データ追加時 77.0 | 384×288 |
| HRNet-W32 + DARK | val 61.2 → 66.9 → 70.7 | 128×96入力。シフトなし → ¼ピクセルシフト → DARK全体 |
| HRNet-W32 + DARK | val 74.4 → 75.6 | 256×192入力 |
| HigherHRNet-W48(bottom-up) | test-dev 70.5 | 640px、マルチスケール。ヒートマップを½解像度まで拡大して小さな人に対応 |
ここから2つのことが読み取れます。
- 入力が小さいほどデコーディングが重要になる。 DARKは128×96で+3.8ポイント、256×192で+1.2ポイントの改善となりました。上記の例でグリッドが粗いほど差が大きかったことと同義です。また、¼ピクセルシフトだけでも61.2から66.9へと5.7ポイントの向上が見られました。
- トップダウンのほうが概して高精度である。 同時期のボトムアップ(61.8〜70.5)とトップダウン(73.7〜77.0)の間には大きな開きがあります。ただし、第8回で見るように処理速度や人数に関する特性は異なります。
7. 限界
- ヒートマップはコストが高い。 関節ごとに2Dマップを描き、精度はマップの解像度に依存します。解像度を上げると計算量が2乗で増加します。第8回のSimCCはこの問題に対処します。
- 速い腕はブレる。 卓球のスイングにおけるラケット側の手首は、露光時間中にブレるため「1つの点」になりません。ボールのブレを扱うBlurBallのような手法は、姿勢推定の分野ではあまり一般的ではありません(第9回と比較してください)。
- オクルージョン(隠蔽)。 胴体に隠れた反対側の腕や、卓球台に隠れた脚は頻繁に間違えられます。COCOのラベルでは隠れた関節も「存在するが見えない」と表示されますが、当てるのは依然として困難です。
8. 我々のプロジェクトとのつながり
- 実測:現在のレベルの姿勢シグナルは判定を覆すのには使えなかった。 TT Scoreの実験で、人物のバウンスボックスの代わりにボールを中心としたボックスをRTMPose-mに入力し、「ボールの近くに手首があるか」でバウンスの候補を絞り込もうとしましたが、正解と偽物をほとんど判別できず、絞り込みを行うとラリー勝者の精度が93.1%から92.0%(60px)・87.6%(90px)に低下しました。「確認必要」という表示としてのみ使用した場合、確認なしの間違った判定は10件から6件に減りましたが、「確認必要」の割合が17%ポイント増加しました(実際の第12回275ラリー、TT Scoreモデル解剖第4回)。
- コーチングにはtop-down方式。 練習動画の姿勢コーチングは1人の人物が主役になるため、top-down方式が適しています。サーバー解析にはRTMDet + RTMPose(top-down)、ブラウザ側ではMediaPipeを使用しています(同じく第4回)。
- 試合には2人から4人。 シングルスなら2人、ダブルスなら4人です。人数が少ないためtop-down方式のコストは大きくありませんが、検出器を別途実行する負担があります。第8回のRTMOのような1ステージ方式が、この用途の候補となります。
TTの一言。 ヒートマップで最も明るいセルだけを選んだ場合、セルが4ピクセルの大きさであれば平均して約1.5ピクセルずれます。「2番目に明るい方向に4分の1セル分移動する」という小さな工夫のコツを1つ使うだけで誤差が半分になり、それがAP 5点の向上につながりました。小さな工夫が大きな違いを生む世界です。
参考文献
- Toshev & Szegedy, DeepPose: Human Pose Estimation via Deep Neural Networks, CVPR 2014. https://arxiv.org/abs/1312.4659
- Tompson et al., Joint Training of a Convolutional Network and a Graphical Model for Human Pose Estimation, NeurIPS 2014. https://arxiv.org/abs/1406.2984
- Cao et al., Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields(OpenPose), CVPR 2017. https://arxiv.org/abs/1611.08050 — ジャーナル版 https://arxiv.org/abs/1812.08008
- Newell et al., Associative Embedding: End-to-End Learning for Joint Detection and Grouping, NeurIPS 2017. https://arxiv.org/abs/1611.05424
- Xiao, Wu, Wei, Simple Baselines for Human Pose Estimation and Tracking, ECCV 2018. https://arxiv.org/abs/1804.06208
- Sun et al., Deep High-Resolution Representation Learning for Human Pose Estimation(HRNet), CVPR 2019. https://arxiv.org/abs/1902.09212
- Zhang et al., Distribution-Aware Coordinate Representation for Human Pose Estimation(DARK), CVPR 2020. https://arxiv.org/abs/1910.06278
- Cheng et al., HigherHRNet: Scale-Aware Representation Learning for Bottom-Up Human Pose Estimation, CVPR 2020. https://arxiv.org/abs/1908.10357
- サンプルコードと出力:
code/07_heatmap_decode.py,code/07_heatmap_decode.out.txt