|
import numpy as np |
|
import torch |
|
|
|
from ..builder import PIPELINES |
|
from ..quaternion import qbetween_np, qinv_np, qmul_np, qrot_np |
|
|
|
face_joint_indx = [2, 1, 17, 16] |
|
fid_l = [7, 10] |
|
fid_r = [8, 11] |
|
|
|
trans_matrix = torch.Tensor([[1.0, 0.0, 0.0], [0.0, 0.0, 1.0], |
|
[0.0, -1.0, 0.0]]) |
|
|
|
|
|
def rigid_transform(relative, data): |
|
|
|
global_positions = data[..., :22 * 3].reshape(data.shape[:-1] + (22, 3)) |
|
global_vel = data[..., 22 * 3:22 * 6].reshape(data.shape[:-1] + (22, 3)) |
|
|
|
relative_rot = relative[0] |
|
relative_t = relative[1:3] |
|
relative_r_rot_quat = np.zeros(global_positions.shape[:-1] + (4, )) |
|
relative_r_rot_quat[..., 0] = np.cos(relative_rot) |
|
relative_r_rot_quat[..., 2] = np.sin(relative_rot) |
|
global_positions = qrot_np(qinv_np(relative_r_rot_quat), global_positions) |
|
global_positions[..., [0, 2]] += relative_t |
|
data[..., :22 * 3] = global_positions.reshape(data.shape[:-1] + (-1, )) |
|
global_vel = qrot_np(qinv_np(relative_r_rot_quat), global_vel) |
|
data[..., 22 * 3:22 * 6] = global_vel.reshape(data.shape[:-1] + (-1, )) |
|
|
|
return data |
|
|
|
|
|
@PIPELINES.register_module() |
|
class SwapSiameseMotion(object): |
|
r"""Swap motion sequences. |
|
|
|
Args: |
|
prob (float): The probability of swapping siamese motions |
|
""" |
|
|
|
def __init__(self, prob=0.5): |
|
self.prob = prob |
|
assert prob >= 0 and prob <= 1.0 |
|
|
|
def __call__(self, results): |
|
if np.random.rand() <= self.prob: |
|
motion1 = results['motion1'] |
|
motion2 = results['motion2'] |
|
results['motion1'] = motion2 |
|
results['motion2'] = motion1 |
|
return results |
|
|
|
def __repr__(self): |
|
repr_str = self.__class__.__name__ + f'(prob={self.prob})' |
|
return repr_str |
|
|
|
|
|
@PIPELINES.register_module() |
|
class ProcessSiameseMotion(object): |
|
r"""Process siamese motion sequences. |
|
The code is borrowed from |
|
https://github.com/tr3e/InterGen/blob/master/utils/utils.py |
|
""" |
|
|
|
def __init__(self, feet_threshold, prev_frames, n_joints, prob): |
|
self.feet_threshold = feet_threshold |
|
self.prev_frames = prev_frames |
|
self.n_joints = n_joints |
|
self.prob = prob |
|
|
|
def process_single_motion(self, motion): |
|
feet_thre = self.feet_threshold |
|
prev_frames = self.prev_frames |
|
n_joints = self.n_joints |
|
'''Uniform Skeleton''' |
|
|
|
|
|
positions = motion[:, :n_joints * 3].reshape(-1, n_joints, 3) |
|
rotations = motion[:, n_joints * 3:] |
|
|
|
positions = np.einsum("mn, tjn->tjm", trans_matrix, positions) |
|
'''Put on Floor''' |
|
floor_height = positions.min(axis=0).min(axis=0)[1] |
|
positions[:, :, 1] -= floor_height |
|
'''XZ at origin''' |
|
root_pos_init = positions[prev_frames] |
|
root_pose_init_xz = root_pos_init[0] * np.array([1, 0, 1]) |
|
positions = positions - root_pose_init_xz |
|
'''All initially face Z+''' |
|
r_hip, l_hip, sdr_r, sdr_l = face_joint_indx |
|
across = root_pos_init[r_hip] - root_pos_init[l_hip] |
|
across = across / np.sqrt((across**2).sum(axis=-1))[..., np.newaxis] |
|
|
|
|
|
forward_init = np.cross(np.array([[0, 1, 0]]), across, axis=-1) |
|
|
|
forward_init = forward_init / np.sqrt((forward_init**2).sum(axis=-1)) |
|
forward_init = forward_init[..., np.newaxis] |
|
|
|
target = np.array([[0, 0, 1]]) |
|
root_quat_init = qbetween_np(forward_init, target) |
|
root_quat_init_for_all = \ |
|
np.ones(positions.shape[:-1] + (4,)) * root_quat_init |
|
|
|
positions = qrot_np(root_quat_init_for_all, positions) |
|
""" Get Foot Contacts """ |
|
|
|
def foot_detect(positions, thres): |
|
velfactor, heightfactor = \ |
|
np.array([thres, thres]), np.array([0.12, 0.05]) |
|
|
|
feet_l_x = \ |
|
(positions[1:, fid_l, 0] - positions[:-1, fid_l, 0]) ** 2 |
|
feet_l_y = \ |
|
(positions[1:, fid_l, 1] - positions[:-1, fid_l, 1]) ** 2 |
|
feet_l_z = \ |
|
(positions[1:, fid_l, 2] - positions[:-1, fid_l, 2]) ** 2 |
|
feet_l_h = positions[:-1, fid_l, 1] |
|
feet_l_sum = feet_l_x + feet_l_y + feet_l_z |
|
feet_l = ((feet_l_sum < velfactor) & (feet_l_h < heightfactor)) |
|
feet_l = feet_l.astype(np.float32) |
|
|
|
feet_r_x = \ |
|
(positions[1:, fid_r, 0] - positions[:-1, fid_r, 0]) ** 2 |
|
feet_r_y = \ |
|
(positions[1:, fid_r, 1] - positions[:-1, fid_r, 1]) ** 2 |
|
feet_r_z = \ |
|
(positions[1:, fid_r, 2] - positions[:-1, fid_r, 2]) ** 2 |
|
feet_r_h = positions[:-1, fid_r, 1] |
|
feet_r_sum = feet_r_x + feet_r_y + feet_r_z |
|
feet_r = ((feet_r_sum < velfactor) & (feet_r_h < heightfactor)) |
|
feet_r = feet_r.astype(np.float32) |
|
return feet_l, feet_r |
|
|
|
feet_l, feet_r = foot_detect(positions, feet_thre) |
|
'''Get Joint Rotation Representation''' |
|
rot_data = rotations |
|
'''Get Joint Rotation Invariant Position Represention''' |
|
joint_positions = positions.reshape(len(positions), -1) |
|
joint_vels = positions[1:] - positions[:-1] |
|
joint_vels = joint_vels.reshape(len(joint_vels), -1) |
|
|
|
data = joint_positions[:-1] |
|
data = np.concatenate([data, joint_vels], axis=-1) |
|
data = np.concatenate([data, rot_data[:-1]], axis=-1) |
|
data = np.concatenate([data, feet_l, feet_r], axis=-1) |
|
|
|
return data, root_quat_init, root_pose_init_xz[None] |
|
|
|
def __call__(self, results): |
|
motion1, root_quat_init1, root_pos_init1 = \ |
|
self.process_single_motion(results['motion1']) |
|
motion2, root_quat_init2, root_pos_init2 = \ |
|
self.process_single_motion(results['motion2']) |
|
r_relative = qmul_np(root_quat_init2, qinv_np(root_quat_init1)) |
|
angle = np.arctan2(r_relative[:, 2:3], r_relative[:, 0:1]) |
|
|
|
xz = qrot_np(root_quat_init1, root_pos_init2 - root_pos_init1)[:, |
|
[0, 2]] |
|
relative = np.concatenate([angle, xz], axis=-1)[0] |
|
motion2 = rigid_transform(relative, motion2) |
|
if np.random.rand() <= self.prob: |
|
motion2, motion1 = motion1, motion2 |
|
motion = np.concatenate((motion1, motion2), axis=-1) |
|
results['motion'] = motion |
|
return results |
|
|
|
def __repr__(self): |
|
repr_str = self.__class__.__name__ |
|
repr_str += f'(feet_threshold={self.feet_threshold})' |
|
repr_str += f'(feet_threshold={self.feet_threshold})' |
|
repr_str += f'(n_joints={self.n_joints})' |
|
repr_str += f'(prob={self.prob})' |
|
return repr_str |
|
|