Download src/utils/motion.py from human-motion-capture/AnyMo: direct link, hf CLI and curl.
- Browser
- Download file 5.96 kB
-
https://huggingface.co/human-motion-capture/AnyMo/resolve/main/src/utils/motion.py
- Command line
-
hf download hf://human-motion-capture/AnyMo/src/utils/motion.py
-
curl -L -o motion.py https://huggingface.co/human-motion-capture/AnyMo/resolve/main/src/utils/motion.py
5.96 kB
| import torch | |
| import numpy as np | |
| from .rotation_conversions import rotation_6d_to_matrix, matrix_to_axis_angle | |
| def accumulate_rotations(relative_rotations): | |
| R_total = [relative_rotations[0]] | |
| for R_rel in relative_rotations[1:]: | |
| R_total.append(np.matmul(R_rel, R_total[-1])) | |
| return np.array(R_total) | |
| def accumulate_rotations_batch(R_rel): | |
| B, T, _, _ = R_rel.shape | |
| R_list = [] | |
| R_prev = R_rel[:, 0] | |
| R_list.append(R_prev) | |
| for t in range(1, T): | |
| R_curr = R_rel[:, t] @ R_prev | |
| R_list.append(R_curr) | |
| R_prev = R_curr | |
| R_out = torch.stack(R_list, dim=1) | |
| return R_out | |
| def recover_from_local_position_fast(final_x: torch.Tensor, njoint=22): | |
| """ | |
| final_x: (B, T, D) | |
| return: (B, T, J, 3) | |
| """ | |
| B, T, _ = final_x.shape | |
| device = final_x.device | |
| # -------- unpack -------- | |
| positions_no_heading = final_x[:, :, 8:8+3*njoint].reshape(B, T, njoint, 3) | |
| velocities_root_xy = final_x[:, :, :2] | |
| global_heading_diff_rot = final_x[:, :, 2:8] | |
| # -------- rotation -------- | |
| R_rel = rotation_6d_to_matrix(global_heading_diff_rot) # (B, T, 3, 3) | |
| R_global = accumulate_rotations_batch(R_rel) # (B, T, 3, 3) | |
| R_inv = R_global.transpose(-1, -2) # inverse | |
| # -------- rotate joints -------- | |
| pos = torch.matmul( | |
| R_inv[:, :, None, :, :], | |
| positions_no_heading[..., None] | |
| ).squeeze(-1) # (B, T, J, 3) | |
| # -------- root velocity -------- | |
| vel_root = torch.zeros((B, T, 3), device=device) | |
| vel_root[:, :, 0] = velocities_root_xy[:, :, 0] | |
| vel_root[:, :, 2] = velocities_root_xy[:, :, 1] | |
| vel_root[:, 1:] = torch.matmul( | |
| R_inv[:, :-1], | |
| vel_root[:, 1:, :, None] | |
| ).squeeze(-1) | |
| # -------- integrate -------- | |
| root_translation = torch.cumsum(vel_root, dim=1) | |
| pos[:, :, :, 0] += root_translation[:, :, 0:1] | |
| pos[:, :, :, 2] += root_translation[:, :, 2:3] | |
| return pos | |
| def recover_from_local_position(final_x, njoint): | |
| if final_x.ndim == 3: | |
| bs, nfrm, _ = final_x.shape | |
| is_batched = True | |
| else: | |
| nfrm, _ = final_x.shape | |
| bs = 1 | |
| is_batched = False | |
| final_x = final_x.reshape(1, *final_x.shape) | |
| positions_no_heading = final_x[:,:,8:8+3*njoint].reshape(bs, nfrm, njoint, 3) | |
| velocities_root_xy_no_heading = final_x[:,:,:2] | |
| global_heading_diff_rot = final_x[:,:,2:8] | |
| positions_with_heading = [] | |
| for b in range(bs): | |
| global_heading_rot = accumulate_rotations(rotation_6d_to_matrix(torch.from_numpy(global_heading_diff_rot[b])).numpy()) | |
| inv_global_heading_rot = np.transpose(global_heading_rot, (0, 2, 1)) | |
| curr_pos_with_heading = np.matmul(np.repeat(inv_global_heading_rot[:, None,:, :], njoint, axis=1), | |
| positions_no_heading[b][...,None]).squeeze(-1) | |
| velocities_root_xyz_no_heading = np.zeros((velocities_root_xy_no_heading[b].shape[0], 3)) | |
| velocities_root_xyz_no_heading[:, 0] = velocities_root_xy_no_heading[b, :, 0] | |
| velocities_root_xyz_no_heading[:, 2] = velocities_root_xy_no_heading[b, :, 1] | |
| velocities_root_xyz_no_heading[1:, :] = np.matmul(inv_global_heading_rot[:-1], | |
| velocities_root_xyz_no_heading[1:, :,None]).squeeze(-1) | |
| root_translation = np.cumsum(velocities_root_xyz_no_heading, axis=0) | |
| curr_pos_with_heading[:, :, 0] += root_translation[:, 0:1] | |
| curr_pos_with_heading[:, :, 2] += root_translation[:, 2:] | |
| positions_with_heading.append(curr_pos_with_heading) | |
| positions_with_heading = np.stack(positions_with_heading, axis=0) | |
| if not is_batched: | |
| positions_with_heading = positions_with_heading.squeeze(0) | |
| return positions_with_heading | |
| def recover_from_local_rotation(final_x, njoint): | |
| nfrm, _ = final_x.shape | |
| rotations_matrix = rotation_6d_to_matrix(torch.from_numpy(final_x[:,8+6*njoint:8+12*njoint]).reshape(nfrm, -1, 6)).numpy() | |
| global_heading_diff_rot = final_x[:,2:8] | |
| velocities_root_xy_no_heading = final_x[:,:2] | |
| positions_no_heading = final_x[:, 8:8+3*njoint].reshape(nfrm, -1, 3) | |
| height = positions_no_heading[:, 0, 1] | |
| global_heading_rot = accumulate_rotations(rotation_6d_to_matrix(torch.from_numpy(global_heading_diff_rot)).numpy()) | |
| inv_global_heading_rot = np.transpose(global_heading_rot, (0, 2, 1)) | |
| # recover root rotation | |
| rotations_matrix[:,0,...] = np.matmul(inv_global_heading_rot, rotations_matrix[:,0,...]) | |
| velocities_root_xyz_no_heading = np.zeros((velocities_root_xy_no_heading.shape[0], 3)) | |
| velocities_root_xyz_no_heading[:, 0] = velocities_root_xy_no_heading[:, 0] | |
| velocities_root_xyz_no_heading[:, 2] = velocities_root_xy_no_heading[:, 1] | |
| velocities_root_xyz_no_heading[1:, :] = np.matmul(inv_global_heading_rot[:-1], velocities_root_xyz_no_heading[1:, :,None]).squeeze(-1) | |
| root_translation = np.cumsum(velocities_root_xyz_no_heading, axis=0) | |
| root_translation[:, 1] = height | |
| nfrm, njoint, _, _ = rotations_matrix.shape | |
| axis_angle = matrix_to_axis_angle(torch.from_numpy(rotations_matrix)).numpy().reshape(nfrm, -1) | |
| global_orient = axis_angle[:, :3] | |
| # y-up -> z-up | |
| # global_orient_mat = torch.from_numpy(rotations_matrix)[:, 0].float() | |
| # rotation_matrix = torch.tensor([[1, 0, 0], [0, 0, 1], [0, -1, 0]]).float() | |
| # global_orient_mat = torch.einsum('ij,tjk->tik', rotation_matrix, global_orient_mat) | |
| # global_orient = matrix_to_axis_angle(global_orient_mat) | |
| # root_translation = torch.einsum('ij,tj->ti', rotation_matrix, torch.from_numpy(root_translation).float()) | |
| return dict( | |
| global_orient = global_orient, | |
| body_pose = axis_angle[:, 3:], | |
| transl = root_translation, | |
| betas = torch.zeros((nfrm, 10)) | |
| ) | |