現在、手の姿勢推定には、2017 年にマックス プランク研究所が提案した MANO パラメトリック モデルを使用し、これに基づいて 3 次元座標を返す技術ソリューションが主流ですが、これは MANO が非常に合理的な構造と明確に定義された順ダイナミクスを備えているためです。木から学びましょう。この記事の目的は、MANO に基づく手の姿勢推定のプロセスを紹介することです。データ処理、MANO の推論プロセス (論文と一致)、手の解剖学的および生物学的特性が含まれますが、これらに限定されません。
1. 手の姿勢推定とは何ですか?
私が手の姿勢推定として理解していることは、
人体の姿勢推定と同じで、手のクローズアップ画像が与えられると、その姿勢 (2D/3D キーポイント) の位置が推定されます (通常 21 )。
以下の図は、最も古典的な実装の 1 つです (パラメーター化されたモデルはありません)。
Encoder-Decoder 構造に手のクローズアップ画像を入力し、Decoder が出力した特徴マップから応答が最も大きい位置を選択し、グラウンドトゥルースを含む 2D ランドマークのヒート マップを生成して損失を計算します。目的は、Decoder によって生成された特徴を使用することです。グラフには、手のさまざまな位置での対応する応答があります。つまり、関心のある点( PoI ) から関心のある領域 ( RoI )の表現の構築に変化します。ネットワークが特定の点に焦点を当てることから範囲に焦点を当てるように変化することで、モデルの汎化能力と複雑な状況における推定のロバスト性が拡張されます。
この方法は、パラメトリック モデル MANO/SMPL が登場する前は姿勢推定の分野で主流でした。
この写真は、2018年にOlha CHERNYTSKAさん(ウクライナ・カトリック大学卒業)の修士論文からのものです
[3]
。
3Dキーポイントの座標は相対座標系で表現されるのが一般的で、手の場合は手首(下図0)/人差し指と手のひらを繋ぐ関節(下図5)を原点として選択するのが一般的です。ローカル座標系 (0, 0, 0 ) 。このアプローチは、 root-relativeとも呼ばれます。
次の図は、上図のノード 5 を原点として相対的な 3 次元座標で表現したものです。次の図を例として、ノード 5 の座標を (0, 0, 0) にしたいとします。一般的には非常に単純です (擬似コード):
img = cv2.imread("xxx.jpg") # 1) 读取手部特写图片
img = normalize(img) # 2) 对图片进行处理(规则化等)
pred_3d = Net(img) # 3) 送入网络进行预测
pred_3d -= pred_3d[5] # 4) 将预测结果变为root-relative的方式.
赤いボックスはノード 5 で、その座標は (0, 0, 0) です。
2.MANOとは何ですか?
近年、CVPR、ECCV、ICCV に関する手の姿勢推定に関する論文はすべて、多かれ少なかれモデルベース、つまりパラメトリック モデルに基づいたソリューションです。その中でも最も主流のパラメトリックモデルは、2017年にSiggraph AsiaでJavier Romero、Dimitrios Tzionas、Michael J. Blackによって出版された「 Embodied Hands: Modeling and Capturing Hands and Bodies Together」です[1]
。
この記事もマックス プランク研究所とインダストリアル ライト アンド マジックが共同で提案した「 SMPL: A Skinned Multi-person Linear Model (2015)」に基づいており[2]
、手のパラメトリック モデルを提案しています。
低解像度、オクルージョン、ノイズに対処するために、
MANO (Hand Model with Articulated and Non-rigid defOrmations) と呼ばれる新しいモデルを
開発しました[1]
。
私の個人的な感覚では、ジェスチャー推定の問題は次のとおりです。
-
自己閉塞: たとえば、下の写真では、中指から小指までが手の甲で塞がれています。
-
手で物体を掴むことによって引き起こされるオクルージョン:
-
低解像度: 全体の構成において手が占めるピクセルの割合は非常に小さいため、ジェスチャーを正確に推定することが困難になります。
確かに、全身/半身で見た場合、ジェスチャーは全身に比べて占めるピクセル数が非常に小さいため、動きを区別すること
が困難ですが、MANOモデルは遷移表現を追加する(または遷移表現を追加する)ことに相当します。画像 -> 3D ポーズの間。経験に基づく強い優先順位により、オクルージョンと低解像度画像を予測できます。
Frankmocap リポジトリからの画像
[4]
事前情報のない方法、つまりモデルフリーの方法を使用すると、通常、このような状況での姿勢推定効果は失敗します。パラメトリック モデル MANO が作成されて以来、MANO は、握手、不十分な照明、その他のシーンを含む、さまざまな手のポーズをとった 31 人の被験者の手の 1000 回の高解像度 3D スキャンから取得されました。
したがって、過去 18 年間にわたる数多くの手の姿勢分析作業によれば、MANO パラメータ化モデルの使用が合理的かつ正確な手の姿勢を推定する上で重要な役割を果たすことが示されています。
なお、手はセグメント化された剛体(多関節物体)であるため、モデリングは依然として困難であり、マックス・プランク研究所は米国アトランタの3dMD社のスキャン装置を使用したが、これには多額の費用がかかると推定されている..., MANOの作り方については、ここでは詳しく説明しませんので、興味のある方は記事のすぐ下に聞いてください。
この写真は、中国科学技術大学の Liu Ligang 氏が教えた games102 コースからのものです
[5]
。
では、3D パラメトリック モデルとしての MANO のパラメータは何でしょうか?
- 778 の頂点と 1538 の面、および 16 のキー ポイント + 5 つの指先ポイントに基づいて
頂点から取得され、完全なハンド チェーンを形成する、またはフォワードキネマティック ツリーと呼ばれます。
下の写真はオックスフォード大学の CVPR2019 論文[7]
「3D Hand Shape and 「イメージ・イン・ザ・ワイルド」のポーズ。
(つまり、図の 16、17、18、19、20 はすべて、所定のルール、コードに従って変形された頂点から取得されます。ノード 9 を例にとると、その 3D 座標は次のように変形されたメッシュ上にあります。頂点が存在する場所を抽出します。
3. ジェスチャー3D姿勢推定のMANO部分の処理ロジック解析重点
下図に示すように、手のクロップ画像がニューラルネットワークに送信され、MANOが必要とするカメラパラメータ(最初の3つ)、θ(3)を含むMANOが必要とする61個のパラメータの値が予測されます。 -51)、β( 51:61)。 ここで、θ はMANO でポーズを制御するために使用されるパラメータであり、βは MANO で形状を制御するために使用されるパラメータです。
その中でも、ニューラル ネットワークの設計は、入力と出力の構造に従って設計されている限り比較的単純であり、最も古典的な実装ソリューションは、UCB と Max Planck が共同で作成した CVPR2018 論文: HMR です。予測を最適化するための自己回帰法[6]
。MANO に必要な 61 個の係数。
-
入力 (bs, 3, 224, 224) は
画像処理後に取得されたテンソル (NCHW) です。画像の解像度は必要に応じて調整でき、bs はバッチ サイズです。 -
出力は (bs, 61)
で、MANO に必要なパラメータを取得します。これらのパラメータを MANO に入力すると、3 次元姿勢推定結果 (相対座標系における 21 個のキー点の xyz 位置) を取得できます。
3.1 MANOの計算ロジック
下の図は CVPR2020 の「Minimal-Hand」からのもので[8]
、2 つの公式を使用して MANO プロセスを簡単に要約しています。
- 1 T ( β , θ ) = T ‾ + B s ( β ) + B p ( θ ) T(\beta, \theta) = \overline{T} + B_s(\beta) + B_p(\theta)T ( b 、私)=T+Bs( b )+Bp( θ )
この式は形状パラメータβ ∈ R 10 \beta \in R^{10}b∈R1 0とポーズのパラメータθ ∈ R 48 \theta \in R^{48}私∈R4 8が変形され、その変形はB s / p B_{s/p}Bs / p成し遂げる。T ‾ \overline{T}T標準の 3D ハンド メッシュを表します。下の図は MANO のhand_mean
T ‾ \overline{T}T:
ご覧のとおり、MANO のT ‾ \overline{T}T手のひらを平らに広げた姿勢で、アニメーションの分野では一般にTポーズと呼ばれています
。
- 2 M ( β , θ ) = W ( T ( θ , β ) , θ , β , W , J ( θ ) ) M(\beta, \theta) = \mathbf{W}(T(\theta, \beta )、\シータ、\ベータ、W、J(\シータ))M ( b 、私)=W ( T ( θ ,b )、私、b 、わ、J ( θ ) )ステップ①により、変形されたメッシュ
が得られます:T ( θ , β ) T(\theta, \beta)T ( θ ,β )、ステップ 2 の目的は、スキニング操作 (線形ブレンド スキニング) を実行することです。WWWは皮膚の重さ、J ( θ ) J(\theta)J ( θ )はノードの位置です。
3.2 MANOの実際の計算過程
さて、MANO の基本的な処理を理解したところで本題に戻りますが、この記事の目的は、MANO がカム、形状、姿勢のパラメータをどのように処理して関節の回転 (軸と角度を表す) を取得するかを分析することです。
rot_pose_beta_to_mesh
ここでは、次の関数を分析のコアとして使用します。このrot_pose_beta_to_mesh
関数は 3 つの入力パラメーターを受け取り、これらを合わせると、ネットワークによって予測される正確に 61 個のパラメーターになります。
- 腐る∈ R 3 \in R^{3}∈R3
ルートノード (手首 CMC) の回転軸角度。 - ポーズ∈ R 45 \in R^{45}∈R4 5
各指の指先 (TIP 列を除く) と手首、すべてのキー ポイントの軸角度 (15*3=45) を除く、下の図は ECCV2020 BMC からのものです[9]
手のボーンは、灰色の手首(CMC)、黄色のMCP(手のひらと各指の接合部)、緑色のPIP、青色のDIP 、および指先の位置を示すボーンTIPに分かれています。ボーンに「横」という名前が付いているのがわかります…。
- ベータ∈ R 10 \in R^{10}∈R1 0
mano に必要な形状パラメータ
3.2.1 MANO 計算に関係するいくつかの重要なパラメーター
-
kintree_table、parent などのダイナミクスおよび継承関係パラメータ。
下の図に示すように、parent と kintree_table は一連のジェスチャを形成します。kintree_table には
指先が含まれていないことに注意してください。!(関節数は 16 個、指関節 15 個 + 手首関節 1 個のみ)、これも MANO で定義された構造に準拠しています。つまり、上図には 5 つの点 (4,8,12,16,20) がありません。 -
hands_mean
: ここでのhands_meanはmesh_muと同様に
レストの手の軸角度である必要があり、ネットワークが予測したポーズ(軸角度)を加えて処理するという使い方になります。ここでのポーズには TIP スケルトンが含まれていないことに加えて、手首も含まれていないことに
注意してください。
-
mesh_mu
:下図の[1]
式 2 のT (MANO2017 ) ‾ \overline{T}T. それが平均的な形状です。
式 2 から計算されるT p T_pTpコードのvowned v_{posed}に対応します。vポーズをとった_:
-
mesh_pca
: 形状は pca に基づいて形状として最大の 10 次元パラメータを取るため、最大の形状固有値に対応する固有ベクトル ここでの Mesh_pca は、用途に応じて式 4 (MANO2017) の Sn です。
対応するコード:
-
J_regressor
: (SMPL2015) の式 10 に相当し、メッシュ上の頂点 (頂点) をノード (ジョイント) に変えることが目的です。
-
root_rot
: ルートノードとは手首上の点、つまり下図の0点を指し、相対距離を計算するにはこの方法を使用する必要があると理解しています。
-
posedirs
: 以前の分析によると、posedirs
ポーズのブレンド形状パラメータを表す MANO (2017) の式 3 の Pn です。
-
weights
:weights
第 3.1 章式 2 M ( β , θ ) = W ( T ( θ , β ) , θ , β , W , J ( θ ) ) M(\beta, \theta) = \mathbf{W}(T( \theta 、\beta)、\theta、\beta、W、J(\theta))M ( b 、私)=W ( T ( θ ,b )、私、b 、わ、J ( θ ) )のWWW。
3.2.2 回転行列の計算 (Rodrigues)
ここでの主な分析はrodrigues
関数です。この関数の目的は、軸角度 (axis-angle) を回転行列 (回転行列) に[10]
変更することです。次のコードは、回転の単位ノルム軸w ‾ \overline
にn
等しくなります。下図 (SMPL2015) {w} w、R
R = I3 + torch.sin(theta).view(-1, 1, 1) * Sn \
+ (1. - torch.cos(theta).view(-1, 1, 1)) * torch.matmul(Sn, Sn)
SMPL2015の式(1)と同等であり、S(n_)
関数は上記に相当しますSkew(V)
。
def rodrigues(r):
theta = torch.sqrt(torch.sum(torch.pow(r, 2), 1))
def S(n_):
ns = torch.split(n_, 1, 1)
Sn_ = torch.cat([torch.zeros_like(ns[0]), -ns[2], ns[1], ns[2], torch.zeros_like(ns[0]), -ns[0], -ns[1], ns[0],
torch.zeros_like(ns[0])], 1)
Sn_ = Sn_.view(-1, 3, 3)
return Sn_
n = r / (theta.view(-1, 1))
Sn = S(n)
# R = torch.eye(3).unsqueeze(0) + torch.sin(theta).view(-1, 1, 1)*Sn\
# +(1.-torch.cos(theta).view(-1, 1, 1)) * torch.matmul(Sn,Sn)
I3 = Variable(torch.eye(3).unsqueeze(0).cuda())
# R等于 公式 (1)---SMPL
R = I3 + torch.sin(theta).view(-1, 1, 1) * Sn \
+ (1. - torch.cos(theta).view(-1, 1, 1)) * torch.matmul(Sn, Sn)
Sr = S(r)
theta2 = theta ** 2
R2 = I3 + (1. - theta2.view(-1, 1, 1) / 6.) * Sr \
+ (.5 - theta2.view(-1, 1, 1) / 24.) * torch.matmul(Sr, Sr)
idx = np.argwhere((theta < 1e-30).data.cpu().numpy())
if (idx.size):
R[idx, :, :] = R2[idx, :, :]
return R, Sn
3.2.3get_poseweights (poses, bszie)
この関数は、pose_weights
形状が[bs, 135]
、135 = 45 ∗ 3 135 = 45 * 3のプロパティを計算するために使用されます。1 3 5=4 5∗3. 2 つのステップに分かれています
。
-
①
poses
3.2.2 で導入した Rodrigues 関数に最初のフィード ([bs, 16, 3]) を入力します。SMPL2015 によると、その目的は各関節の軸角度を回転行列に変換することです。pose_matrix
は [15xbs, 3、3]
-
②pose_matrix から単位行列を引いたもの。 (MANO2017) の式 3の R n ( θ ) − R n ( θ ∗ ) R_n(θ)- R_n(θ^*)として理解されます。Rん(私)−Rん(私は∗ ):
def get_poseweights(poses, bsize):
# pose: batch x 24 x 3
pose_matrix, _ = rodrigues(poses[:, 1:, :].contiguous().view(-1, 3))
# pose_matrix, _ = rodrigues(poses.view(-1,3))
pose_matrix = pose_matrix - Variable(torch.from_numpy(
np.repeat(np.expand_dims(np.eye(3, dtype=np.float32), 0), bsize * (keypoints_num - 1), axis=0)).cuda())
pose_matrix = pose_matrix.view(bsize, -1)
return pose_matrix
3.3rot_pose_beta_to_mesh
コーミング
① 最初のステップは、ポーズとv_shapeを計算することです。
⚫ ポーズ: ポーズはネットワークによって予測されますaxis angle
+ hand_mean
(静止ポーズ)、さらに root_rot (手首の位置。コードでは (0,0,0) として記述されます。これは相対位置であり、root-relative を構築した結果です) . [bs、16、3]
⚫ v_shape: SMPL2015 の式 10 の T に対応します‾ \overline{T}T+ パート B [bs、778、3]
対応するコード:
② ステップ 2 では、 pose_weights、v_used 、およびJ_ownedを計算します。
⚫pose_weightsが渡されます
pose_weights = get_poseweights(poses, batch_size)
計算された。具体的な分析については、get_poseweights
3.2.3の機能紹介を参照してください。
⚫ v_posed は <3D Hand Shape and Pose from Images in the wild, CVPR2019> の公式 2 のT ( β , θ ) T(β, θ)T ( b 、θ )、これは MANO2017 の式 2 でもあります。
⚫ J_posed は SMPL2015 の式 10 であり、その機能は頂点をジョイントに変えることです。([bs, 16, 3])
③ 3 番目のステップは、results_globalとT, vを計算することです。
⚫ J_owned (bs, 16, 3)からJ_owned_split (16, bs, 3) に変更します。つまり、ここでの処理ロジックは、バッチ単位の次元ではなく、指のノードに従って処理されます。
⚫ 同様に、posesから取得したposses_split、posses_splitから取得したangle_matrixがあります。
⚫ results_globalはキネマティック ツリーに基づいて計算され、各カレント ノードの関節位置は、親ノードとカレント ノードの回転行列に基づく行列乗算によって取得されます。
results_global は 16 個のフィンガー ノードの 3D xyz でもあります。[(bs ,4, 4), (bs, 4, 4), … , (bs ,4, 4)]. 親ノードは単にその上のノードであることに注意してください。現在のノード
、ルートノードではありません~。以前にこの問題を説明した図があります。
⚫ T は、前の結果とウェイトを乗算して取得されます。ここでのウェイトは、スキンされたブレンド ウェイトWWです。W。
⚫ Vはスキニング処理後の最終的な変形ノード、Jtrはハンドノードの最終的な 3D 位置セットであり、**指先 (TIP ボーン)** の 5 つの関節の位置は V に基づいて取得されることに注意してください。
さらに、最終的に正しい結果を出力するには、(ルート ノードの回転角度に従って)
VとJtrを再度回転する必要があります。
④ 最後のステップは、標準 MANO モデルから TIP スケルトンの関節位置を見つけることです。
この方法では、手動で MANO モデルの頂点を確認する必要があります。例として親指をとり、頂点番号 745 を示し
ます。頂点を配置します。 v とノード Jtr の両方が、ルート ノード (手首) の回転行列に従って回転されます。
最後に、ローカル座標系の 3D 座標 (ルート相対) を取得するために、ノード 5 を (0, 0, 0) として取得する処理を実行します。したがって、ノード 5 の位置を V から減算する必要があります。そしてJtr .. _
4. まとめ
上記の分析に基づいて、最終的に、各手の画像に対応する 21 のキーポイントと、ねじり後の 778 個の頂点すべての 3Dxyz (ルート相対) を取得しました (MANO の手モデルには 778 個の頂点があります)。
ご不明な点がございましたら、お問い合わせください〜
参考文献
[1] MANO2017
[2] SMPL2015
[3] OlgaChernytska/3D-Hand-Pose-Estimation
[4] Frankmocap Facebook
[5] 「幾何モデリングと処理 (GMP)」
[6] HMR CVPR2018
[8] Minimal Hand CVPR2020
[9] ] hand-biomechanical-constraints (ECCV2020)
[10]回転行列: 軸と角度