|
|
|
import torch |
|
from tqdm import tqdm |
|
|
|
import numpy as np |
|
from utils.transforms import * |
|
|
|
import pickle |
|
from typing import Optional |
|
|
|
|
|
import os |
|
|
|
|
|
|
|
smpl_joints = [ |
|
"root", |
|
"lhip", |
|
"rhip", |
|
"belly", |
|
"lknee", |
|
"rknee", |
|
"spine", |
|
"lankle", |
|
"rankle", |
|
"chest", |
|
"ltoes", |
|
"rtoes", |
|
"neck", |
|
"linshoulder", |
|
"rinshoulder", |
|
"head", |
|
"lshoulder", |
|
"rshoulder", |
|
"lelbow", |
|
"relbow", |
|
"lwrist", |
|
"rwrist", |
|
|
|
|
|
] |
|
|
|
smpl_parents = [ |
|
-1, |
|
0, |
|
0, |
|
0, |
|
1, |
|
2, |
|
3, |
|
4, |
|
5, |
|
6, |
|
7, |
|
8, |
|
9, |
|
9, |
|
9, |
|
12, |
|
13, |
|
14, |
|
16, |
|
17, |
|
18, |
|
19, |
|
|
|
|
|
] |
|
|
|
smpl_offsets = [ |
|
[0.0, 0.0, 0.0], |
|
[0.05858135, -0.08228004, -0.01766408], |
|
[-0.06030973, -0.09051332, -0.01354254], |
|
[0.00443945, 0.12440352, -0.03838522], |
|
[0.04345142, -0.38646945, 0.008037], |
|
[-0.04325663, -0.38368791, -0.00484304], |
|
[0.00448844, 0.1379564, 0.02682033], |
|
[-0.01479032, -0.42687458, -0.037428], |
|
[0.01905555, -0.4200455, -0.03456167], |
|
[-0.00226458, 0.05603239, 0.00285505], |
|
[0.04105436, -0.06028581, 0.12204243], |
|
[-0.03483987, -0.06210566, 0.13032329], |
|
[-0.0133902, 0.21163553, -0.03346758], |
|
[0.07170245, 0.11399969, -0.01889817], |
|
[-0.08295366, 0.11247234, -0.02370739], |
|
[0.01011321, 0.08893734, 0.05040987], |
|
[0.12292141, 0.04520509, -0.019046], |
|
[-0.11322832, 0.04685326, -0.00847207], |
|
[0.2553319, -0.01564902, -0.02294649], |
|
[-0.26012748, -0.01436928, -0.03126873], |
|
[0.26570925, 0.01269811, -0.00737473], |
|
[-0.26910836, 0.00679372, -0.00602676], |
|
|
|
|
|
] |
|
|
|
|
|
def set_line_data_3d(line, x): |
|
line.set_data(x[:, :2].T) |
|
line.set_3d_properties(x[:, 2]) |
|
|
|
|
|
def set_scatter_data_3d(scat, x, c): |
|
scat.set_offsets(x[:, :2]) |
|
scat.set_3d_properties(x[:, 2], "z") |
|
scat.set_facecolors([c]) |
|
|
|
|
|
def get_axrange(poses): |
|
pose = poses[0] |
|
x_min = pose[:, 0].min() |
|
x_max = pose[:, 0].max() |
|
|
|
y_min = pose[:, 1].min() |
|
y_max = pose[:, 1].max() |
|
|
|
z_min = pose[:, 2].min() |
|
z_max = pose[:, 2].max() |
|
|
|
xdiff = x_max - x_min |
|
ydiff = y_max - y_min |
|
zdiff = z_max - z_min |
|
|
|
biggestdiff = max([xdiff, ydiff, zdiff]) |
|
return biggestdiff |
|
|
|
|
|
def plot_single_pose(num, poses, lines, ax, axrange, scat, contact): |
|
pose = poses[num] |
|
static = contact[num] |
|
indices = [7, 8, 10, 11] |
|
|
|
for i, (point, idx) in enumerate(zip(scat, indices)): |
|
position = pose[idx : idx + 1] |
|
color = "r" if static[i] else "g" |
|
set_scatter_data_3d(point, position, color) |
|
|
|
for i, (p, line) in enumerate(zip(smpl_parents, lines)): |
|
|
|
if i == 0: |
|
continue |
|
|
|
data = np.stack((pose[i], pose[p]), axis=0) |
|
set_line_data_3d(line, data) |
|
|
|
if num == 0: |
|
if isinstance(axrange, int): |
|
axrange = (axrange, axrange, axrange) |
|
xcenter, ycenter, zcenter = 0, 0, 2.5 |
|
stepx, stepy, stepz = axrange[0] / 2, axrange[1] / 2, axrange[2] / 2 |
|
|
|
x_min, x_max = xcenter - stepx, xcenter + stepx |
|
y_min, y_max = ycenter - stepy, ycenter + stepy |
|
z_min, z_max = zcenter - stepz, zcenter + stepz |
|
|
|
ax.set_xlim(x_min, x_max) |
|
ax.set_ylim(y_min, y_max) |
|
ax.set_zlim(z_min, z_max) |
|
|
|
|
|
class SMPLSkeleton: |
|
def __init__( |
|
self, device=None, |
|
): |
|
offsets = smpl_offsets |
|
parents = smpl_parents |
|
assert len(offsets) == len(parents) |
|
|
|
self._offsets = torch.Tensor(offsets).to(device) |
|
self._parents = np.array(parents) |
|
self._compute_metadata() |
|
|
|
def _compute_metadata(self): |
|
self._has_children = np.zeros(len(self._parents)).astype(bool) |
|
for i, parent in enumerate(self._parents): |
|
if parent != -1: |
|
self._has_children[parent] = True |
|
|
|
self._children = [] |
|
for i, parent in enumerate(self._parents): |
|
self._children.append([]) |
|
for i, parent in enumerate(self._parents): |
|
if parent != -1: |
|
self._children[parent].append(i) |
|
|
|
def forward(self, rotations, root_positions): |
|
""" |
|
Perform forward kinematics using the given trajectory and local rotations. |
|
Arguments (where N = batch size, L = sequence length, J = number of joints): |
|
-- rotations: (N, L, J, 3) tensor of axis-angle rotations describing the local rotations of each joint. |
|
-- root_positions: (N, L, 3) tensor describing the root joint positions. |
|
""" |
|
assert len(rotations.shape) == 4 |
|
assert len(root_positions.shape) == 3 |
|
|
|
rotations = axis_angle_to_quaternion(rotations) |
|
|
|
positions_world = [] |
|
rotations_world = [] |
|
|
|
expanded_offsets = self._offsets.expand( |
|
rotations.shape[0], |
|
rotations.shape[1], |
|
self._offsets.shape[0], |
|
self._offsets.shape[1], |
|
) |
|
|
|
|
|
for i in range(self._offsets.shape[0]): |
|
if self._parents[i] == -1: |
|
positions_world.append(root_positions) |
|
rotations_world.append(rotations[:, :, 0]) |
|
else: |
|
positions_world.append( |
|
quaternion_apply( |
|
rotations_world[self._parents[i]], expanded_offsets[:, :, i] |
|
) |
|
+ positions_world[self._parents[i]] |
|
) |
|
if self._has_children[i]: |
|
rotations_world.append( |
|
quaternion_multiply( |
|
rotations_world[self._parents[i]], rotations[:, :, i] |
|
) |
|
) |
|
else: |
|
|
|
rotations_world.append(None) |
|
|
|
return torch.stack(positions_world, dim=3).permute(0, 1, 3, 2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JOINT_MAP = { |
|
'OP Nose': 24, 'OP Neck': 12, 'OP RShoulder': 17, |
|
'OP RElbow': 19, 'OP RWrist': 21, 'OP LShoulder': 16, |
|
'OP LElbow': 18, 'OP LWrist': 20, 'OP MidHip': 0, |
|
'OP RHip': 2, 'OP RKnee': 5, 'OP RAnkle': 8, |
|
'OP LHip': 1, 'OP LKnee': 4, 'OP LAnkle': 7, |
|
'OP REye': 25, 'OP LEye': 26, 'OP REar': 27, |
|
'OP LEar': 28, 'OP LBigToe': 29, 'OP LSmallToe': 30, |
|
'OP LHeel': 31, 'OP RBigToe': 32, 'OP RSmallToe': 33, 'OP RHeel': 34, |
|
'Right Ankle': 8, 'Right Knee': 5, 'Right Hip': 45, |
|
'Left Hip': 46, 'Left Knee': 4, 'Left Ankle': 7, |
|
'Right Wrist': 21, 'Right Elbow': 19, 'Right Shoulder': 17, |
|
'Left Shoulder': 16, 'Left Elbow': 18, 'Left Wrist': 20, |
|
'Neck (LSP)': 47, 'Top of Head (LSP)': 48, |
|
'Pelvis (MPII)': 49, 'Thorax (MPII)': 50, |
|
'Spine (H36M)': 51, 'Jaw (H36M)': 52, |
|
'Head (H36M)': 53, 'Nose': 24, 'Left Eye': 26, |
|
'Right Eye': 25, 'Left Ear': 28, 'Right Ear': 27 |
|
} |
|
JOINT_NAMES = [ |
|
'OP Nose', 'OP Neck', 'OP RShoulder', |
|
'OP RElbow', 'OP RWrist', 'OP LShoulder', |
|
'OP LElbow', 'OP LWrist', 'OP MidHip', |
|
'OP RHip', 'OP RKnee', 'OP RAnkle', |
|
'OP LHip', 'OP LKnee', 'OP LAnkle', |
|
'OP REye', 'OP LEye', 'OP REar', |
|
'OP LEar', 'OP LBigToe', 'OP LSmallToe', |
|
'OP LHeel', 'OP RBigToe', 'OP RSmallToe', 'OP RHeel', |
|
'Right Ankle', 'Right Knee', 'Right Hip', |
|
'Left Hip', 'Left Knee', 'Left Ankle', |
|
'Right Wrist', 'Right Elbow', 'Right Shoulder', |
|
'Left Shoulder', 'Left Elbow', 'Left Wrist', |
|
'Neck (LSP)', 'Top of Head (LSP)', |
|
'Pelvis (MPII)', 'Thorax (MPII)', |
|
'Spine (H36M)', 'Jaw (H36M)', |
|
'Head (H36M)', 'Nose', 'Left Eye', |
|
'Right Eye', 'Left Ear', 'Right Ear' |
|
] |
|
BASE_DATA_DIR = "/data2/TSMC_data/base_data" |
|
JOINT_IDS = {JOINT_NAMES[i]: i for i in range(len(JOINT_NAMES))} |
|
JOINT_REGRESSOR_TRAIN_EXTRA = os.path.join(BASE_DATA_DIR, 'J_regressor_extra.npy') |
|
SMPL_MEAN_PARAMS = os.path.join(BASE_DATA_DIR, 'smpl_mean_params.npz') |
|
SMPL_MODEL_DIR = BASE_DATA_DIR |
|
H36M_TO_J17 = [6, 5, 4, 1, 2, 3, 16, 15, 14, 11, 12, 13, 8, 10, 0, 7, 9] |
|
H36M_TO_J14 = H36M_TO_J17[:14] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|