You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
564 lines
14 KiB
564 lines
14 KiB
"""SMPLH/SMPLX joint name constants, body-part indices, and OpenPose mapping."""
|
|
|
|
import os
|
|
|
|
import numpy as np
|
|
import torch
|
|
|
|
SMPLH_JOINT_NAMES = [
|
|
"pelvis",
|
|
"left_hip",
|
|
"right_hip",
|
|
"spine1",
|
|
"left_knee",
|
|
"right_knee",
|
|
"spine2",
|
|
"left_ankle",
|
|
"right_ankle",
|
|
"spine3",
|
|
"left_foot",
|
|
"right_foot",
|
|
"neck",
|
|
"left_collar",
|
|
"right_collar",
|
|
"head",
|
|
"left_shoulder",
|
|
"right_shoulder",
|
|
"left_elbow",
|
|
"right_elbow",
|
|
"left_wrist",
|
|
"right_wrist",
|
|
"left_index1",
|
|
"left_index2",
|
|
"left_index3",
|
|
"left_middle1",
|
|
"left_middle2",
|
|
"left_middle3",
|
|
"left_pinky1",
|
|
"left_pinky2",
|
|
"left_pinky3",
|
|
"left_ring1",
|
|
"left_ring2",
|
|
"left_ring3",
|
|
"left_thumb1",
|
|
"left_thumb2",
|
|
"left_thumb3",
|
|
"right_index1",
|
|
"right_index2",
|
|
"right_index3",
|
|
"right_middle1",
|
|
"right_middle2",
|
|
"right_middle3",
|
|
"right_pinky1",
|
|
"right_pinky2",
|
|
"right_pinky3",
|
|
"right_ring1",
|
|
"right_ring2",
|
|
"right_ring3",
|
|
"right_thumb1",
|
|
"right_thumb2",
|
|
"right_thumb3",
|
|
"nose",
|
|
"right_eye",
|
|
"left_eye",
|
|
"right_ear",
|
|
"left_ear",
|
|
"left_big_toe",
|
|
"left_small_toe",
|
|
"left_heel",
|
|
"right_big_toe",
|
|
"right_small_toe",
|
|
"right_heel",
|
|
"left_thumb",
|
|
"left_index",
|
|
"left_middle",
|
|
"left_ring",
|
|
"left_pinky",
|
|
"right_thumb",
|
|
"right_index",
|
|
"right_middle",
|
|
"right_ring",
|
|
"right_pinky",
|
|
]
|
|
|
|
SMPLH_LEFT_LEG = ["left_hip", "left_knee", "left_ankle", "left_foot"]
|
|
SMPLH_RIGHT_LEG = ["right_hip", "right_knee", "right_ankle", "right_foot"]
|
|
SMPLH_LEFT_ARM = ["left_collar", "left_shoulder", "left_elbow", "left_wrist"]
|
|
SMPLH_RIGHT_ARM = ["right_collar", "right_shoulder", "right_elbow", "right_wrist"]
|
|
SMPLH_HEAD = ["neck", "head"]
|
|
SMPLH_SPINE = ["spine1", "spine2", "spine3"]
|
|
|
|
# name to 21 index (without pelvis, hand, and extra)
|
|
_name_2_idx = {j: i for i, j in enumerate(SMPLH_JOINT_NAMES[1:22])}
|
|
SMPLH_PART_IDX = {
|
|
"left_leg": [_name_2_idx[x] for x in SMPLH_LEFT_LEG],
|
|
"right_leg": [_name_2_idx[x] for x in SMPLH_RIGHT_LEG],
|
|
"left_arm": [_name_2_idx[x] for x in SMPLH_LEFT_ARM],
|
|
"right_arm": [_name_2_idx[x] for x in SMPLH_RIGHT_ARM],
|
|
"two_legs": [_name_2_idx[x] for x in SMPLH_LEFT_LEG + SMPLH_RIGHT_LEG],
|
|
"left_arm_and_leg": [_name_2_idx[x] for x in SMPLH_LEFT_ARM + SMPLH_LEFT_LEG],
|
|
"right_arm_and_leg": [_name_2_idx[x] for x in SMPLH_RIGHT_ARM + SMPLH_RIGHT_LEG],
|
|
}
|
|
|
|
# name to full index
|
|
_name_2_idx_full = {j: i for i, j in enumerate(SMPLH_JOINT_NAMES)}
|
|
SMPLH_PART_IDX_FULL = {
|
|
"lower_body": [_name_2_idx_full[x] for x in ["pelvis"] + SMPLH_LEFT_LEG + SMPLH_RIGHT_LEG]
|
|
}
|
|
|
|
# ===== ⬇️ Fitting optimizer ⬇️ ===== #
|
|
SMPL_JOINTS = {
|
|
"hips": 0,
|
|
"leftUpLeg": 1,
|
|
"rightUpLeg": 2,
|
|
"spine": 3,
|
|
"leftLeg": 4,
|
|
"rightLeg": 5,
|
|
"spine1": 6,
|
|
"leftFoot": 7,
|
|
"rightFoot": 8,
|
|
"spine2": 9,
|
|
"leftToeBase": 10,
|
|
"rightToeBase": 11,
|
|
"neck": 12,
|
|
"leftShoulder": 13,
|
|
"rightShoulder": 14,
|
|
"head": 15,
|
|
"leftArm": 16,
|
|
"rightArm": 17,
|
|
"leftForeArm": 18,
|
|
"rightForeArm": 19,
|
|
"leftHand": 20,
|
|
"rightHand": 21,
|
|
}
|
|
|
|
# chosen virtual mocap markers that are "keypoints" to work with
|
|
KEYPT_VERTS = [
|
|
4404,
|
|
920,
|
|
3076,
|
|
3169,
|
|
823,
|
|
4310,
|
|
1010,
|
|
1085,
|
|
4495,
|
|
4569,
|
|
6615,
|
|
3217,
|
|
3313,
|
|
6713,
|
|
6785,
|
|
3383,
|
|
6607,
|
|
3207,
|
|
1241,
|
|
1508,
|
|
4797,
|
|
4122,
|
|
1618,
|
|
1569,
|
|
5135,
|
|
5040,
|
|
5691,
|
|
5636,
|
|
5404,
|
|
2230,
|
|
2173,
|
|
2108,
|
|
134,
|
|
3645,
|
|
6543,
|
|
3123,
|
|
3024,
|
|
4194,
|
|
1306,
|
|
182,
|
|
3694,
|
|
4294,
|
|
744,
|
|
]
|
|
|
|
|
|
# From https://github.com/vchoutas/smplify-x/blob/master/smplifyx/utils.py
|
|
# Please see license for usage restrictions.
|
|
def smpl_to_openpose(
|
|
model_type="smplx",
|
|
use_hands=True,
|
|
use_face=True,
|
|
use_face_contour=False,
|
|
openpose_format="coco25",
|
|
):
|
|
"""Returns the indices of the permutation that maps SMPL to OpenPose
|
|
|
|
Parameters
|
|
----------
|
|
model_type: str, optional
|
|
The type of SMPL-like model that is used. The default mapping
|
|
returned is for the SMPLX model
|
|
use_hands: bool, optional
|
|
Flag for adding to the returned permutation the mapping for the
|
|
hand keypoints. Defaults to True
|
|
use_face: bool, optional
|
|
Flag for adding to the returned permutation the mapping for the
|
|
face keypoints. Defaults to True
|
|
use_face_contour: bool, optional
|
|
Flag for appending the facial contour keypoints. Defaults to False
|
|
openpose_format: bool, optional
|
|
The output format of OpenPose. For now only COCO-25 and COCO-19 is
|
|
supported. Defaults to 'coco25'
|
|
|
|
"""
|
|
if openpose_format.lower() == "coco25":
|
|
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":
|
|
body_mapping = np.array(
|
|
[
|
|
52,
|
|
12,
|
|
17,
|
|
19,
|
|
21,
|
|
16,
|
|
18,
|
|
20,
|
|
0,
|
|
2,
|
|
5,
|
|
8,
|
|
1,
|
|
4,
|
|
7,
|
|
53,
|
|
54,
|
|
55,
|
|
56,
|
|
57,
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
62,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
mapping = [body_mapping]
|
|
if use_hands:
|
|
lhand_mapping = np.array(
|
|
[
|
|
20,
|
|
34,
|
|
35,
|
|
36,
|
|
63,
|
|
22,
|
|
23,
|
|
24,
|
|
64,
|
|
25,
|
|
26,
|
|
27,
|
|
65,
|
|
31,
|
|
32,
|
|
33,
|
|
66,
|
|
28,
|
|
29,
|
|
30,
|
|
67,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
rhand_mapping = np.array(
|
|
[
|
|
21,
|
|
49,
|
|
50,
|
|
51,
|
|
68,
|
|
37,
|
|
38,
|
|
39,
|
|
69,
|
|
40,
|
|
41,
|
|
42,
|
|
70,
|
|
46,
|
|
47,
|
|
48,
|
|
71,
|
|
43,
|
|
44,
|
|
45,
|
|
72,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
mapping += [lhand_mapping, rhand_mapping]
|
|
return np.concatenate(mapping)
|
|
# SMPLX
|
|
elif model_type == "smplx":
|
|
body_mapping = np.array(
|
|
[
|
|
55,
|
|
12,
|
|
17,
|
|
19,
|
|
21,
|
|
16,
|
|
18,
|
|
20,
|
|
0,
|
|
2,
|
|
5,
|
|
8,
|
|
1,
|
|
4,
|
|
7,
|
|
56,
|
|
57,
|
|
58,
|
|
59,
|
|
60,
|
|
61,
|
|
62,
|
|
63,
|
|
64,
|
|
65,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
mapping = [body_mapping]
|
|
if use_hands:
|
|
lhand_mapping = np.array(
|
|
[
|
|
20,
|
|
37,
|
|
38,
|
|
39,
|
|
66,
|
|
25,
|
|
26,
|
|
27,
|
|
67,
|
|
28,
|
|
29,
|
|
30,
|
|
68,
|
|
34,
|
|
35,
|
|
36,
|
|
69,
|
|
31,
|
|
32,
|
|
33,
|
|
70,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
rhand_mapping = np.array(
|
|
[
|
|
21,
|
|
52,
|
|
53,
|
|
54,
|
|
71,
|
|
40,
|
|
41,
|
|
42,
|
|
72,
|
|
43,
|
|
44,
|
|
45,
|
|
73,
|
|
49,
|
|
50,
|
|
51,
|
|
74,
|
|
46,
|
|
47,
|
|
48,
|
|
75,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
|
|
mapping += [lhand_mapping, rhand_mapping]
|
|
if use_face:
|
|
# end_idx = 127 + 17 * use_face_contour
|
|
face_mapping = np.arange(76, 127 + 17 * use_face_contour, dtype=np.int32)
|
|
mapping += [face_mapping]
|
|
|
|
return np.concatenate(mapping)
|
|
else:
|
|
raise ValueError("Unknown model type: {}".format(model_type))
|
|
elif openpose_format == "coco19":
|
|
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],
|
|
dtype=np.int32,
|
|
)
|
|
elif model_type == "smplh":
|
|
body_mapping = np.array(
|
|
[52, 12, 17, 19, 21, 16, 18, 20, 0, 2, 5, 8, 1, 4, 7, 53, 54, 55, 56],
|
|
dtype=np.int32,
|
|
)
|
|
mapping = [body_mapping]
|
|
if use_hands:
|
|
lhand_mapping = np.array(
|
|
[
|
|
20,
|
|
34,
|
|
35,
|
|
36,
|
|
57,
|
|
22,
|
|
23,
|
|
24,
|
|
58,
|
|
25,
|
|
26,
|
|
27,
|
|
59,
|
|
31,
|
|
32,
|
|
33,
|
|
60,
|
|
28,
|
|
29,
|
|
30,
|
|
61,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
rhand_mapping = np.array(
|
|
[
|
|
21,
|
|
49,
|
|
50,
|
|
51,
|
|
62,
|
|
37,
|
|
38,
|
|
39,
|
|
63,
|
|
40,
|
|
41,
|
|
42,
|
|
64,
|
|
46,
|
|
47,
|
|
48,
|
|
65,
|
|
43,
|
|
44,
|
|
45,
|
|
66,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
mapping += [lhand_mapping, rhand_mapping]
|
|
return np.concatenate(mapping)
|
|
# SMPLX
|
|
elif model_type == "smplx":
|
|
body_mapping = np.array(
|
|
[55, 12, 17, 19, 21, 16, 18, 20, 0, 2, 5, 8, 1, 4, 7, 56, 57, 58, 59],
|
|
dtype=np.int32,
|
|
)
|
|
mapping = [body_mapping]
|
|
if use_hands:
|
|
lhand_mapping = np.array(
|
|
[
|
|
20,
|
|
37,
|
|
38,
|
|
39,
|
|
60,
|
|
25,
|
|
26,
|
|
27,
|
|
61,
|
|
28,
|
|
29,
|
|
30,
|
|
62,
|
|
34,
|
|
35,
|
|
36,
|
|
63,
|
|
31,
|
|
32,
|
|
33,
|
|
64,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
rhand_mapping = np.array(
|
|
[
|
|
21,
|
|
52,
|
|
53,
|
|
54,
|
|
65,
|
|
40,
|
|
41,
|
|
42,
|
|
66,
|
|
43,
|
|
44,
|
|
45,
|
|
67,
|
|
49,
|
|
50,
|
|
51,
|
|
68,
|
|
46,
|
|
47,
|
|
48,
|
|
69,
|
|
],
|
|
dtype=np.int32,
|
|
)
|
|
|
|
mapping += [lhand_mapping, rhand_mapping]
|
|
if use_face:
|
|
face_mapping = np.arange(70, 70 + 51 + 17 * use_face_contour, dtype=np.int32)
|
|
mapping += [face_mapping]
|
|
|
|
return np.concatenate(mapping)
|
|
else:
|
|
raise ValueError("Unknown model type: {}".format(model_type))
|
|
else:
|
|
raise ValueError("Unknown joint format: {}".format(openpose_format))
|