SMPL模型
关节点定义如下图
每个不同的2d数据集都会涉及到joint_mapper,即re-order the SMPL joints to some other convention, 例如coco数据集。
from .vertex_ids import vertex_ids as VERTEX_IDS
if vertex_ids is None:
vertex_ids = VERTEX_IDS['smplh']
self.vertex_joint_selector = VertexJointSelector(vertex_ids=vertex_ids, **kwargs)
joints = self.vertex_joint_selector(vertices, joints)
if self.joint_mapper is not None:
joints = self.joint_mapper(joints)
vertex_ids = {
'smplh': {
'nose': 332, 'reye': 6260, 'leye': 2800, 'rear': 4071, 'lear': 583, 'rthumb': 6191, 'rindex': 5782,
'rmiddle': 5905, 'rring': 6016, 'rpinky': 6133, 'lthumb': 2746, 'lindex': 2319, 'lmiddle': 2445, 'lring': 2556,
'lpinky': 2673, 'LBigToe': 3216, 'LSmallToe': 3326, 'LHeel': 3387, 'RBigToe': 6617, 'RSmallToe': 6624,
'RHeel': 6787
},
'smplx': {
'nose': 9120, 'reye': 9929, 'leye': 9448, 'rear': 616, 'lear': 6, 'rthumb': 8079, 'rindex': 7669,
'rmiddle': 7794, 'rring': 7905, 'rpinky': 8022, 'lthumb': 5361, 'lindex': 4933, 'lmiddle': 5058, 'lring': 5169,
'lpinky': 5286, 'LBigToe': 5770, 'LSmallToe': 5780, 'LHeel': 8846, 'RBigToe': 8463, 'RSmallToe': 8474,
'RHeel': 8635
},
'mano': {
'thumb': 744, 'index': 320, 'middle': 443, 'ring': 554, 'pinky': 671
}
看了下VertexJointsSelector,其中的逻辑就是在官方定义的joints基础上,从组成mesh的vertexes中再挑选出若干有实质语义的点,补充进joints中,接在后面。默认会把面部的nose, reye, leye, rear, lear五点补充进去,再选择把哪些点补充进去,就取决于初始化参数。当use_feet_keypoints为True时,会把脚部6点补充进去。当use_hands为True时,会把手部10点补充进去。
官方定义的joints,
SMPL: NUM_BODY_JOINTS = 23, NUM_JOINTS = 23
SMPLH: NUM_BODY_JOINTS = 21, NUM_HAND_JOINTS = 15, NUM_JOINTS = NUM_BODY_JOINTS + 2 * NUM_HAND_JOINTS = 51
SMPLX: NUM_BODY_JOINTS = 21, NUM_HAND_JOINTS = 15, NUM_FACE_JOINTS = 3, NUM_JOINTS = NUM_BODY_JOINTS + 2 * NUM_HAND_JOINTS + NUM_FACE_JOINTS = 54
FLAME模型
FLAME:Faces Learned with an Articulated Model and Expressions,是头部模型,有68个landmarks,前17个landmark为人脸轮廓点,后51个landmark为人脸内部关键点。
openpose模型
smplify-x用到了openpose的body/face/hand三个部分的点位,生成json结果的结构化定义如下。body为25点,具体点位定义如下图所示。hand分左右手,每只手21个关键点,face用的是FLAME模型的68点位。
"people": [{
"pose_keypoint_2d": [25*3],
"hand_left_keypoints_2d": [20*3],
"hand_right_keypoints_2d": [20*3],
"face_keypoints_2d": [68*3],
"gender_pd":,
"gender_gt":,
}]
想要将smpl/smplh/smplx模型的joints映射为openpose的点位格式时,index的映射关系如下
if model_type == 'smpl':
return np.array([24, 12, 17, 19, 21, 16, 18, 20, 0, 2, 5, 8, 1, 4,
7, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], dtype=np.int32)
elif model_type == 'smplh':
mapping = [body_mapping, lhand_mapping, rhand_mapping]
elif model_type == 'smplx':
mapping = [body_mapping, lhand_mapping, rhand_mapping, face_mapping]
相机模型
class PerspectiveCamera(nn.Module):
def __init__(self, rotation=None, translation=None,
focal_length_x=None, focal_length_y=None, batch_size=1,
center=None, dtype=torch.float32, **kwargs):
rotation = nn.Parameter(rotation, requires_grad=True)
translation = nn.Parameters(translation, requires_grad=True)
def forward(self, points):
创建一个透视变换相机,初始化参数为rotation旋转矩阵,translation平移向量,focal_length_x x方向焦距,focal_length_y y方向焦距,batch_size相机个数,center相平面的中心坐标。如果没主动设置,默认焦距为5000。 在这个相机模型里,需要梯度的有rotation,translation。前向部分,完成3d点投影的工作。主要是根据rotation和translation将坐标从世界坐标系转至相机坐标系,再根据相机投影矩阵,将坐标从相机坐标系转换至像素坐标系。
训练损失
E
(
β
,
θ
,
ψ
)
=
E
J
(
β
,
θ
;
K
,
J
e
s
t
)
+
E
θ
b
(
θ
b
)
+
E
θ
f
(
θ
f
)
+
E
θ
h
(
θ
h
)
+
E
α
(
θ
b
)
+
E
β
(
β
)
+
E
ε
(
ψ
)
+
E
?
(
β
,
θ
,
ψ
)
\begin{aligned} E(\beta, \theta, \psi) &= E_J(\beta, \theta; K, J_{est}) \\ &+ E_{\theta_b}(\theta_b) + E_{\theta_f}(\theta_f) + E_{\theta_h}(\theta_h) + E_{\alpha}(\theta_b) \\ &+ E_{\beta}(\beta) + E_\varepsilon(\psi) \\ &+ E_{\varsigma}(\beta, \theta, \psi) \end{aligned}
E(β,θ,ψ)?=EJ?(β,θ;K,Jest?)+Eθb??(θb?)+Eθf??(θf?)+Eθh??(θh?)+Eα?(θb?)+Eβ?(β)+Eε?(ψ)+E??(β,θ,ψ)? 第1个data_term是关节点2d投影误差,K是相机投影矩阵。第2~5是Pose Priors, 第6~7是Shape和Expression Priors,最后一个是interpenetration penalty。
|