from scipy.spatial.transform import Rotation as R
# Convert axis-angle vector to rotation matrix
def axis_angle_to_matrix(axis_angle):
return R.from_rotvec(axis_angle).as_matrix()
def compute_smpl_joint_positions(pose_world, trans_world, joint_hierarchy, joint_rest_positions):
Compute the global joint positions in 3D based on SMPL model pose and rest positions.
:param pose_world: (24x3) array of axis-angle rotations for each joint in world space
:param trans_world: (3) translation of the root joint (pelvis) in world space
:param joint_hierarchy: List of parent indices for each joint
:param joint_rest_positions: (24x3) rest positions of the joints (T-pose)
:return: (24x3) global joint positions in 3D world space
num_joints = len(joint_hierarchy) + 1 # We have 24 joints (Pelvis + 23 others)
joint_positions = np.zeros((num_joints, 3)) # To store the global positions of each joint
joint_rotations = np.zeros((num_joints, 3, 3)) # To store the global rotation matrices for each joint
# Start with the root joint (Pelvis)
joint_positions[0] = trans_world
joint_rotations[0] = np.eye(3) # The pelvis has no rotation initially
# Iterate over each joint (starting from index 1) and compute its position
for i in range(1, num_joints):
parent_idx = joint_hierarchy[i - 1]
# Convert axis-angle to rotation matrix for the current joint (already in world space)
joint_rotation_matrix = axis_angle_to_matrix(pose_world[i])
# Compute the global rotation for the current joint
joint_rotations[i] = joint_rotations[parent_idx] @ joint_rotation_matrix
# Compute the global position for the current joint
joint_positions[i] = joint_positions[parent_idx] + joint_rotations[parent_idx] @ joint_rest_positions[i]
# SMPL Joint hierarchy (same as before)
1, # Left Knee -> Left Hip
2, # Right Knee -> Right Hip
4, # Left Ankle -> Left Knee
5, # Right Ankle -> Right Knee
7, # Left Toe -> Left Ankle
8, # Right Toe -> Right Ankle
12, # Left Shoulder -> Neck
12, # Right Shoulder -> Neck
13, # Left Elbow -> Left Shoulder
14, # Right Elbow -> Right Shoulder
15, # Left Wrist -> Left Elbow
16, # Right Wrist -> Right Elbow
17, # Left Hand -> Left Wrist
18, # Right Hand -> Right Wrist
# SMPL default T-pose joint positions (in meters)
smpl_rest_pose = np.array([
[0.000000, 0.000000, 0.000000], # Pelvis (root joint)
[0.065231, -0.084792, 0.004014], # Left Hip
[-0.065231, -0.084792, 0.004014], # Right Hip
[0.000000, 0.059053, 0.000000], # Spine
[0.091713, -0.370266, 0.004094], # Left Knee
[-0.091713, -0.370266, 0.004094], # Right Knee
[0.000000, 0.206089, 0.000000], # Spine 2
[0.097469, -0.738293, 0.004016], # Left Ankle
[-0.097469, -0.738293, 0.004016], # Right Ankle
[0.000000, 0.451070, 0.000000], # Spine 3
[0.097515, -0.846017, -0.085256], # Left Toe
[-0.097515, -0.846017, -0.085256], # Right Toe
[0.000000, 0.628839, 0.000000], # Neck
[0.000000, 0.673400, 0.000000], # Head
[0.173363, 0.573362, 0.000052], # Left Shoulder
[-0.173363, 0.573362, 0.000052], # Right Shoulder
[0.325267, 0.572304, 0.000147], # Left Elbow
[-0.325267, 0.572304, 0.000147], # Right Elbow
[0.431036, 0.572345, 0.000304], # Left Wrist
[-0.431036, 0.572345, 0.000304], # Right Wrist
[0.498760, 0.571109, 0.000320], # Left Hand
[-0.498760, 0.571109, 0.000320], # Right Hand
[0.000000, 0.719092, 0.025512], # Nose
[0.000000, 0.731636, 0.037334], # Eyes
# Assume pose_world_data and trans_world_data are in shape (num_frames, 24, 3) and (num_frames, 3), respectively
# Replace with actual data
pose_world_data = np.random.randn(num_frames, 24, 3) # Example pose_world data for all frames
trans_world_data = np.random.randn(num_frames, 3) # Example trans_world data for all frames
# Iterate over each frame and compute joint positions
for frame_idx in range(num_frames):
pose_world = pose_world_data[frame_idx] # Pose for the current frame (24x3 in world space)
trans_world = trans_world_data[frame_idx] # Translation for the current frame (3 in world space)
# Compute the joint positions for the current frame
joint_positions = compute_smpl_joint_positions(pose_world, trans_world, smpl_joint_hierarchy, smpl_rest_pose)
all_joint_positions.append(joint_positions)
# Convert the list to an array (num_frames, 24, 3)
all_joint_positions = np.array(all_joint_positions)
# Print the joint positions for the first frame
print("Joint positions for the first frame (in world space):")
print(all_joint_positions[0])