Motion Representation#

Motion representation utilities and kinematics helpers.

Skeleton#

Skeleton definitions and utilities used across kimodo.

class kimodo.skeleton.SkeletonBase(folder=None, name=None, load=True, **kwargs)[source]#

Bases: <Mock object at 0x7c5620423f40>[]

Base class that stores a skeleton hierarchy and helper metadata.

Subclasses define the static joint layout (joint names and parent links) and semantic groups (feet, hands, hips). This class builds index mappings, parent tensors, and convenience helpers used by kinematics, constraints, and motion conversion utilities.

bone_order_names_with_parents = None#
hip_joint_names = None#
__init__(folder=None, name=None, load=True, **kwargs)[source]#

Initialize a skeleton instance and optional neutral-pose assets.

Parameters:
  • folder – Folder containing serialized skeleton assets (for example joints.p and optional standard_t_pose_global_offsets_rots.p).

  • name – Optional runtime name used to validate subclass compatibility.

  • load – Whether to load tensor assets from folder.

  • **kwargs – Unused extra config keys kept for config compatibility.

name = None#
root_idx = None#
bone_order_names_no_root = None#
foot_joint_names = None#
foot_joint_idx = None#
hip_joint_idx = None#
expand_joint_names(joint_names)[source]#

Expand base EE names [LeftFoot, RightFoot, LeftHand, RightHand] actual joint names to constrain position and rotations.

Parameters:

joint_names – list of list of base EE names to constrain

Returns:

list of list of joint names to constrain rotations pos_joint_names: list of list of joint names to constrain positions

Return type:

rot_joint_names

expand_joint_names_batched(joint_names)[source]#

Expand base EE names [LeftFoot, RightFoot, LeftHand, RightHand] actual joint names to constrain position and rotations.

Parameters:

joint_names – list of list of base EE names to constrain

Returns:

list of list of joint names to constrain rotations pos_joint_names: list of list of joint names to constrain positions

Return type:

rot_joint_names

property device#

Device where neutral-joint buffers are stored.

Returns ‘cpu’ if neutral_joints is not present.

fk(local_joint_rots, root_positions)[source]#

Run forward kinematics for this skeleton layout.

Parameters:
  • local_joint_rots – Local joint rotation matrices with shape (…, J, 3, 3).

  • root_positions – Root translations with shape (…, 3).

Returns:

Tuple of (global_joint_rots, posed_joints, posed_joints_norootpos).

to_standard_tpose(local_rot_mats)[source]#

Convert local rotations into the skeleton’s standard T-pose frame.

from_standard_tpose(local_rot_mats)[source]#

Convert local rotations from the skeleton’s standard T-pose frame.

global_rots_to_local_rots(global_joint_rots)[source]#

Convert global joint rotations to local rotations for this hierarchy.

get_skel_slice(skeleton)[source]#

Build index mapping from another skeleton into this skeleton order.

Parameters:

skeleton – Source skeleton whose joint order is used by input tensors.

Returns:

A list of source indices ordered as self.bone_order_names.

Raises:

ValueError – If at least one required joint is missing from skeleton.

class kimodo.skeleton.G1Skeleton34(folder=None, name=None, load=True, **kwargs)[source]#

Bases: SkeletonBase

Unitree G1 skeleton with 32 articulated joints plus 2 toe endpoints.

name = 'g1skel34'#
right_foot_joint_names = ['right_ankle_roll_skel', 'right_toe_base']#
left_foot_joint_names = ['left_ankle_roll_skel', 'left_toe_base']#
right_hand_joint_names = ['right_wrist_yaw_skel', 'right_hand_roll_skel']#
left_hand_joint_names = ['left_wrist_yaw_skel', 'left_hand_roll_skel']#
hip_joint_names = ['right_hip_pitch_skel', 'left_hip_pitch_skel']#
bone_order_names_with_parents = [('pelvis_skel', None), ('left_hip_pitch_skel', 'pelvis_skel'), ('left_hip_roll_skel', 'left_hip_pitch_skel'), ('left_hip_yaw_skel', 'left_hip_roll_skel'), ('left_knee_skel', 'left_hip_yaw_skel'), ('left_ankle_pitch_skel', 'left_knee_skel'), ('left_ankle_roll_skel', 'left_ankle_pitch_skel'), ('left_toe_base', 'left_ankle_roll_skel'), ('right_hip_pitch_skel', 'pelvis_skel'), ('right_hip_roll_skel', 'right_hip_pitch_skel'), ('right_hip_yaw_skel', 'right_hip_roll_skel'), ('right_knee_skel', 'right_hip_yaw_skel'), ('right_ankle_pitch_skel', 'right_knee_skel'), ('right_ankle_roll_skel', 'right_ankle_pitch_skel'), ('right_toe_base', 'right_ankle_roll_skel'), ('waist_yaw_skel', 'pelvis_skel'), ('waist_roll_skel', 'waist_yaw_skel'), ('waist_pitch_skel', 'waist_roll_skel'), ('left_shoulder_pitch_skel', 'waist_pitch_skel'), ('left_shoulder_roll_skel', 'left_shoulder_pitch_skel'), ('left_shoulder_yaw_skel', 'left_shoulder_roll_skel'), ('left_elbow_skel', 'left_shoulder_yaw_skel'), ('left_wrist_roll_skel', 'left_elbow_skel'), ('left_wrist_pitch_skel', 'left_wrist_roll_skel'), ('left_wrist_yaw_skel', 'left_wrist_pitch_skel'), ('left_hand_roll_skel', 'left_wrist_yaw_skel'), ('right_shoulder_pitch_skel', 'waist_pitch_skel'), ('right_shoulder_roll_skel', 'right_shoulder_pitch_skel'), ('right_shoulder_yaw_skel', 'right_shoulder_roll_skel'), ('right_elbow_skel', 'right_shoulder_yaw_skel'), ('right_wrist_roll_skel', 'right_elbow_skel'), ('right_wrist_pitch_skel', 'right_wrist_roll_skel'), ('right_wrist_yaw_skel', 'right_wrist_pitch_skel'), ('right_hand_roll_skel', 'right_wrist_yaw_skel')]#
class kimodo.skeleton.SOMASkeleton30(folder=None, name=None, load=True, **kwargs)[source]#

Bases: SkeletonBase

Compact 30-joint SOMA variant with reduced hand and end-effector detail.

name = 'somaskel30'#
right_foot_joint_names = ['RightFoot', 'RightToeBase']#
left_foot_joint_names = ['LeftFoot', 'LeftToeBase']#
right_hand_joint_names = ['RightHand', 'RightHandMiddleEnd']#
left_hand_joint_names = ['LeftHand', 'LeftHandMiddleEnd']#
hip_joint_names = ['RightLeg', 'LeftLeg']#
bone_order_names_with_parents = [('Hips', None), ('Spine1', 'Hips'), ('Spine2', 'Spine1'), ('Chest', 'Spine2'), ('Neck1', 'Chest'), ('Neck2', 'Neck1'), ('Head', 'Neck2'), ('Jaw', 'Head'), ('LeftEye', 'Head'), ('RightEye', 'Head'), ('LeftShoulder', 'Chest'), ('LeftArm', 'LeftShoulder'), ('LeftForeArm', 'LeftArm'), ('LeftHand', 'LeftForeArm'), ('LeftHandThumbEnd', 'LeftHand'), ('LeftHandMiddleEnd', 'LeftHand'), ('RightShoulder', 'Chest'), ('RightArm', 'RightShoulder'), ('RightForeArm', 'RightArm'), ('RightHand', 'RightForeArm'), ('RightHandThumbEnd', 'RightHand'), ('RightHandMiddleEnd', 'RightHand'), ('LeftLeg', 'Hips'), ('LeftShin', 'LeftLeg'), ('LeftFoot', 'LeftShin'), ('LeftToeBase', 'LeftFoot'), ('RightLeg', 'Hips'), ('RightShin', 'RightLeg'), ('RightFoot', 'RightShin'), ('RightToeBase', 'RightFoot')]#
property somaskel77#
to_SOMASkeleton77(local_joint_rots_subset)[source]#
from_SOMASkeleton77(local_joint_rots_full)[source]#

Extract the 30-joint subset from 77-joint local rotation data.

output_to_SOMASkeleton77(output)[source]#

Convert model output dict from somaskel30 to somaskel77.

Expands local_rot_mats to 77 joints, re-runs FK for global_rot_mats and posed_joints. Foot contacts are expanded from 4 channels to 6 (toe-end copies toe-base contact).

class kimodo.skeleton.SOMASkeleton77(folder=None, name=None, load=True, **kwargs)[source]#

Bases: SkeletonBase

High-detail 77-joint SOMA skeleton with full finger and toe chains.

name = 'somaskel77'#
right_foot_joint_names = ['RightFoot', 'RightToeBase', 'RightToeEnd']#
left_foot_joint_names = ['LeftFoot', 'LeftToeBase', 'LeftToeEnd']#
right_hand_joint_names = ['RightHand', 'RightHandThumb1', 'RightHandThumb2', 'RightHandThumb3', 'RightHandThumbEnd', 'RightHandIndex1', 'RightHandIndex2', 'RightHandIndex3', 'RightHandIndex4', 'RightHandIndexEnd', 'RightHandMiddle1', 'RightHandMiddle2', 'RightHandMiddle3', 'RightHandMiddle4', 'RightHandMiddleEnd', 'RightHandRing1', 'RightHandRing2', 'RightHandRing3', 'RightHandRing4', 'RightHandRingEnd', 'RightHandPinky1', 'RightHandPinky2', 'RightHandPinky3', 'RightHandPinky4', 'RightHandPinkyEnd']#
left_hand_joint_names = ['LeftHand', 'LeftHandThumb1', 'LeftHandThumb2', 'LeftHandThumb3', 'LeftHandThumbEnd', 'LeftHandIndex1', 'LeftHandIndex2', 'LeftHandIndex3', 'LeftHandIndex4', 'LeftHandIndexEnd', 'LeftHandMiddle1', 'LeftHandMiddle2', 'LeftHandMiddle3', 'LeftHandMiddle4', 'LeftHandMiddleEnd', 'LeftHandRing1', 'LeftHandRing2', 'LeftHandRing3', 'LeftHandRing4', 'LeftHandRingEnd', 'LeftHandPinky1', 'LeftHandPinky2', 'LeftHandPinky3', 'LeftHandPinky4', 'LeftHandPinkyEnd']#
hip_joint_names = ['RightLeg', 'LeftLeg']#
bone_order_names_with_parents = [('Hips', None), ('Spine1', 'Hips'), ('Spine2', 'Spine1'), ('Chest', 'Spine2'), ('Neck1', 'Chest'), ('Neck2', 'Neck1'), ('Head', 'Neck2'), ('HeadEnd', 'Head'), ('Jaw', 'Head'), ('LeftEye', 'Head'), ('RightEye', 'Head'), ('LeftShoulder', 'Chest'), ('LeftArm', 'LeftShoulder'), ('LeftForeArm', 'LeftArm'), ('LeftHand', 'LeftForeArm'), ('LeftHandThumb1', 'LeftHand'), ('LeftHandThumb2', 'LeftHandThumb1'), ('LeftHandThumb3', 'LeftHandThumb2'), ('LeftHandThumbEnd', 'LeftHandThumb3'), ('LeftHandIndex1', 'LeftHand'), ('LeftHandIndex2', 'LeftHandIndex1'), ('LeftHandIndex3', 'LeftHandIndex2'), ('LeftHandIndex4', 'LeftHandIndex3'), ('LeftHandIndexEnd', 'LeftHandIndex4'), ('LeftHandMiddle1', 'LeftHand'), ('LeftHandMiddle2', 'LeftHandMiddle1'), ('LeftHandMiddle3', 'LeftHandMiddle2'), ('LeftHandMiddle4', 'LeftHandMiddle3'), ('LeftHandMiddleEnd', 'LeftHandMiddle4'), ('LeftHandRing1', 'LeftHand'), ('LeftHandRing2', 'LeftHandRing1'), ('LeftHandRing3', 'LeftHandRing2'), ('LeftHandRing4', 'LeftHandRing3'), ('LeftHandRingEnd', 'LeftHandRing4'), ('LeftHandPinky1', 'LeftHand'), ('LeftHandPinky2', 'LeftHandPinky1'), ('LeftHandPinky3', 'LeftHandPinky2'), ('LeftHandPinky4', 'LeftHandPinky3'), ('LeftHandPinkyEnd', 'LeftHandPinky4'), ('RightShoulder', 'Chest'), ('RightArm', 'RightShoulder'), ('RightForeArm', 'RightArm'), ('RightHand', 'RightForeArm'), ('RightHandThumb1', 'RightHand'), ('RightHandThumb2', 'RightHandThumb1'), ('RightHandThumb3', 'RightHandThumb2'), ('RightHandThumbEnd', 'RightHandThumb3'), ('RightHandIndex1', 'RightHand'), ('RightHandIndex2', 'RightHandIndex1'), ('RightHandIndex3', 'RightHandIndex2'), ('RightHandIndex4', 'RightHandIndex3'), ('RightHandIndexEnd', 'RightHandIndex4'), ('RightHandMiddle1', 'RightHand'), ('RightHandMiddle2', 'RightHandMiddle1'), ('RightHandMiddle3', 'RightHandMiddle2'), ('RightHandMiddle4', 'RightHandMiddle3'), ('RightHandMiddleEnd', 'RightHandMiddle4'), ('RightHandRing1', 'RightHand'), ('RightHandRing2', 'RightHandRing1'), ('RightHandRing3', 'RightHandRing2'), ('RightHandRing4', 'RightHandRing3'), ('RightHandRingEnd', 'RightHandRing4'), ('RightHandPinky1', 'RightHand'), ('RightHandPinky2', 'RightHandPinky1'), ('RightHandPinky3', 'RightHandPinky2'), ('RightHandPinky4', 'RightHandPinky3'), ('RightHandPinkyEnd', 'RightHandPinky4'), ('LeftLeg', 'Hips'), ('LeftShin', 'LeftLeg'), ('LeftFoot', 'LeftShin'), ('LeftToeBase', 'LeftFoot'), ('LeftToeEnd', 'LeftToeBase'), ('RightLeg', 'Hips'), ('RightShin', 'RightLeg'), ('RightFoot', 'RightShin'), ('RightToeBase', 'RightFoot'), ('RightToeEnd', 'RightToeBase')]#
property relaxed_hands_rest_pose#
class kimodo.skeleton.SMPLXSkeleton22(folder=None, name=None, load=True, **kwargs)[source]#

Bases: SkeletonBase

SMPL-X skeleton with body-only 22 joints.

name = 'smplx22'#
right_foot_joint_names = ['right_ankle', 'right_foot']#
left_foot_joint_names = ['left_ankle', 'left_foot']#
right_hand_joint_names = ['right_wrist']#
left_hand_joint_names = ['left_wrist']#
hip_joint_names = ['right_hip', 'left_hip']#
bone_order_names_with_parents = [('pelvis', None), ('left_hip', 'pelvis'), ('right_hip', 'pelvis'), ('spine1', 'pelvis'), ('left_knee', 'left_hip'), ('right_knee', 'right_hip'), ('spine2', 'spine1'), ('left_ankle', 'left_knee'), ('right_ankle', 'right_knee'), ('spine3', 'spine2'), ('left_foot', 'left_ankle'), ('right_foot', 'right_ankle'), ('neck', 'spine3'), ('left_collar', 'spine3'), ('right_collar', 'spine3'), ('head', 'neck'), ('left_shoulder', 'left_collar'), ('right_shoulder', 'right_collar'), ('left_elbow', 'left_shoulder'), ('right_elbow', 'right_shoulder'), ('left_wrist', 'left_elbow'), ('right_wrist', 'right_elbow')]#
kimodo.skeleton.batch_rigid_transform(rot_mats, joints, parents, root_idx)[source]#

Perform batch rigid transformation on a skeletal structure.

Parameters:
  • rot_mats – Local rotation matrices for each joint: (B, J, 3, 3)

  • joints – Initial joint positions: (B, J, 3)

  • parents – Tensor indicating the parent of each joint: (J,)

  • root_idx (int) – index of the root

Returns:

Transformed joint positions after applying forward kinematics.

kimodo.skeleton.fk(
local_joint_rots,
root_positions,
skeleton,
root_positions_is_global=True,
)[source]#

Compute global joint rotations and positions from local rotations.

Parameters:
  • local_joint_rots – Local rotation matrices with shape (…, J, 3, 3).

  • root_positions – Root translations with shape (…, 3).

  • skeleton – Skeleton object exposing neutral_joints, joint_parents, and root_idx.

  • root_positions_is_global – If True, neutral joints are recentered so root translations are interpreted in world space.

Returns:

Tuple (global_joint_rots, posed_joints, posed_joints_norootpos).

kimodo.skeleton.build_skeleton(
nbjoints,
assets_folder=PosixPath('/home/drempe/projects/motion_foundation_model/kimodo-oss-release/mfm-oss/kimodo/assets/skeletons'),
)[source]#

Instantiate a known skeleton class from its joint count.

Supported joint counts: 30 (SOMA compact), 34 (G1), 77 (SOMA full), 22 (SMPLX).

Parameters:
  • nbjoints – Number of joints expected in the skeleton representation.

  • assets_folder – Base skeleton-assets directory containing per-skeleton subfolders.

Returns:

A configured SkeletonBase subclass instance.

Raises:

ValueError – If nbjoints does not match a registered skeleton.

kimodo.skeleton.global_rots_to_local_rots(global_joint_rots, skeleton)[source]#

Convert global rotations to local rotations using a skeleton hierarchy.

Parameters:
  • global_joint_rots – Global rotation matrices with shape (…, J, 3, 3).

  • skeleton – Skeleton object exposing joint_parents and root_idx.

Returns:

Local rotation matrices with the same leading shape as the input.

kimodo.skeleton.to_standard_tpose(local_rot_mats, skeleton)[source]#

Re-express local rotations in the skeleton’s standard T-pose convention.

Parameters:
  • local_rot_mats – Local rotation matrices with shape (…, J, 3, 3).

  • skeleton – Skeleton object exposing global_rot_offsets, joint_parents, root_idx, and nbjoints.

Returns:

Tuple (new_local_rot_mats, new_global_rot_mats) in the standard frame.

Forward Kinematics#

Forward-kinematics primitives for articulated skeletons.

kimodo.skeleton.kinematics.fk(
local_joint_rots,
root_positions,
skeleton,
root_positions_is_global=True,
)[source]#

Compute global joint rotations and positions from local rotations.

Parameters:
  • local_joint_rots – Local rotation matrices with shape (…, J, 3, 3).

  • root_positions – Root translations with shape (…, 3).

  • skeleton – Skeleton object exposing neutral_joints, joint_parents, and root_idx.

  • root_positions_is_global – If True, neutral joints are recentered so root translations are interpreted in world space.

Returns:

Tuple (global_joint_rots, posed_joints, posed_joints_norootpos).

kimodo.skeleton.kinematics.compute_idx_levels(parents)[source]#

Group joint indices by hierarchy depth for level-wise FK updates.

Parameters:

parents – Parent index tensor of shape (J,) with root parent -1.

Returns:

List of index tensors, where each tensor contains joints at one depth.

kimodo.skeleton.kinematics.batch_rigid_transform(rot_mats, joints, parents, root_idx)[source]#

Perform batch rigid transformation on a skeletal structure.

Parameters:
  • rot_mats – Local rotation matrices for each joint: (B, J, 3, 3)

  • joints – Initial joint positions: (B, J, 3)

  • parents – Tensor indicating the parent of each joint: (J,)

  • root_idx (int) – index of the root

Returns:

Transformed joint positions after applying forward kinematics.

kimodo.skeleton.kinematics.skeleton_idx_levs(skeleton, device)[source]#

Return the skeleton’s cached FK joint levels on device, or None if absent.

The levels are buffers, so they normally already sit on device (moved with the module); the .to below is a fallback for skeletons used on a foreign device and would compile device_put copies into the FK graph — keep the skeleton on the compute device instead.

kimodo.skeleton.kinematics.joints_from_global_rots(
global_joint_rots,
root_positions,
skeleton,
root_positions_is_global=True,
return_norootpos=False,
)[source]#

Joint positions directly from GLOBAL rotations: p_j = p_parent + R_g[parent] @ rel_j.

fk composes global rotations from local ones level by level; when the caller already has the global rotations (decoded from the features) and does not need local rotations, this skips the global->local conversion and all the rotation compositions.

Parameters:
  • global_joint_rots – Global rotation matrices with shape (..., J, 3, 3).

  • root_positions – Root translations with shape (..., 3).

  • skeleton – Skeleton exposing neutral_joints, joint_parents, root_idx.

  • root_positions_is_global – see fk.

  • return_norootpos – also return the root-local positions (root at the origin, no dependence on root_positions) that the posed joints are built from — the FK position loss wants exactly these, so it can consume them directly instead of re-subtracting the root (which would also route gradients through root_positions for nothing).

Returns:

Posed joints (..., J, 3) (identical to fk’s posed_joints); if return_norootpos also the root-local positions (..., J, 3).

Motion Representations#

Base motion representation: feature layout, normalization, and conditioning helpers.

class kimodo.motion_rep.reps.base.FeatureLayout(
size_dict,
last_root_feature,
local_root_size_dict=<factory>,
)[source]#

Bases: object

Declarative feature layout of a motion representation.

A representation is a concatenation of named feature blocks (root first, then body). Declaring the layout as data — instead of subclass attributes set before super().__init__() — means a new representation (e.g. one with extra scene or object-contact blocks) is a layout + the transform methods, not a base-class contract to reverse-engineer.

size_dict#

Ordered mapping of feature block name -> per-frame torch.Size. Block order defines the feature vector layout.

Type:

dict

last_root_feature#

Name of the last block belonging to the (global) root; every block up to and including it forms the root slice, the rest is the body.

Type:

str

local_root_size_dict#

Layout of the derived local-root features (used by global_root_to_local_root), not part of the stored feature vector.

Type:

dict

size_dict#
last_root_feature#
local_root_size_dict#
__init__(
size_dict,
last_root_feature,
local_root_size_dict=<factory>,
)#
class kimodo.motion_rep.reps.base.MotionRepBase(skeleton, fps, stats_path=None, layout=None)[source]#

Bases: <Mock object at 0x7c56203257b0>[]

Base class for motion representations used in generation and conditioning.

Subclasses pass a FeatureLayout describing their feature blocks and implement transform-specific methods such as __call__, inverse, rotate, translate_2d and create_conditions.

This is an nn.Module (holding no parameters) so that the Stats and skeleton buffers follow the model when it is moved to a device, instead of being re-transferred from CPU on every normalize/unnormalize/FK call.

__init__(skeleton, fps, stats_path=None, layout=None)[source]#

Initialize feature slicing metadata and optional normalization stats.

property root_pos_name#

Name of the 3D root-position feature block (root_pos or smooth_root_pos).

get_root_pos(features, fallback_to_smooth=True)[source]#

Extract root positions from a feature tensor.

Supports both root_pos and smooth_root_pos representations.

recenter_root_motion(
root_motion,
center_frame_index,
is_normalized,
to_normalize,
return_center_pos=False,
)[source]#

Translate root x/z so a selected frame becomes the local origin.

Assumes the root feature block starts with a 3D position (root_pos or smooth_root_pos), like global_root_to_local_root.

global_root_to_local_root(
root_features,
normalized,
lengths,
)[source]#

Convert global root features to local-root motion features.

Parameters:
  • root_features – Root feature tensor containing root position and global heading, shaped [B, T, D_root].

  • normalized – Whether root_features are normalized.

  • lengths – Optional valid lengths per sequence.

Returns:

Tensor [B, T, 4] with local root rotational velocity, planar velocity, and global root height.

local_root_to_global_root(
local_root_features,
normalized,
lengths=None,
)[source]#

Convert local-root motion features back to global root features.

Exact inverse of global_root_to_local_root(), up to the integration constants that the local representation does not store: the recovered heading and planar (x, z) position are relative to frame 0 (zero heading and origin at frame 0).

Parameters:
  • local_root_features – Local-root tensor [B, T, 4] with rotational velocity, planar velocity, and global root height.

  • normalized – Whether local_root_features are normalized (the returned global root features are then normalized as well).

  • lengths – Optional valid lengths per sequence (unused; kept for symmetry with global_root_to_local_root).

Returns:

Tensor [B, T, D_root] with root position and global heading.

get_root_heading_angle(features, normalized=False)[source]#

Compute root heading angle from cosine/sine heading features.

With normalized=True only the two heading channels get unnormalized (arctan2 needs raw values), instead of unnormalizing the whole feature tensor first. features may be the full feature tensor or just the root block — the heading slice indices are valid for both since the root block leads the feature layout.

get_first_heading_angle(features, normalized)[source]#

Return the frame-0 heading angle for each sequence in the batch.

Parameters:
  • features – Motion features of shape [B, T, motion_rep_dim].

  • normalized – Whether features is normalized.

Returns:

Tensor of shape [B] with the per-sequence heading at frame 0.

rotate_to(
features,
target_angle,
return_delta_angle=False,
)[source]#

Rotate each sequence so frame-0 heading matches target_angle.

rotate_to_zero(features, return_delta_angle=False)[source]#

Rotate each sequence so frame-0 heading becomes zero.

canonicalize_random_heading(
features,
return_delta_angle=False,
return_delta_pos=False,
)[source]#

Canonicalize each sequence to a RANDOM frame-0 heading: frame-0 root (x, z) goes to the origin (like canonicalize) but the heading is randomized instead of zeroed — the training-time heading augmentation. Rotation and recentering belong together here: a rotate-only augmentation leaves the window’s world offset in the root features, so models trained directly on loader output (kimodo) see a shifted root distribution.

translate_2d_to(
features,
target_2d_pos,
return_delta_pos=False,
)[source]#

Translate each sequence so frame-0 root (x, z) matches a target.

translate_2d_to_zero(features, return_delta_pos=False)[source]#

Translate each sequence so frame-0 root (x, z) is at the origin.

canonicalize(features, normalized=False)[source]#

Canonicalize heading and planar position at frame 0.

normalize(features)[source]#

Normalize features.

unnormalize(features)[source]#

Undo feature normalization.

feature_indices(feature_name)[source]#

All flat feature indices of a feature block.

joint_feature_indices(
feature_name,
joint_names,
joint_order=None,
)[source]#

Flat feature indices covering joint_names inside a per-joint feature block.

The per-joint width (e.g. 3 for positions, 6 for cont6d rotations) is derived from the block size. joint_order is the joint ordering of the block; it defaults to the skeleton bone order.

This is the single place mapping (feature block, joint) -> feature columns; both the training-time mask builders and the inference-time constraint conditioning rely on it.

Results are memoized per instance (deterministic in slice_dict/skeleton, which are fixed after init): the mask builders call this per keyframe per sample, and rebuilding the name->index dict each call dominated their cost. The cache stays tiny (one entry per distinct (block, joints, order) combination). Callers must not mutate the returned array.

extract_root(features)[source]#

Extract the global-root features from a full motion tensor.

extract_body(features)[source]#

Extract the body features from a full motion tensor.

concat_root_body(root, body)[source]#

Concatenate root and body features into a full motion feature tensor.

create_conditions_from_constraints(
constraints_lst,
length,
to_normalize,
device,
)[source]#

Create a conditioning tensor and mask from constraint objects.

create_conditions_from_constraints_batched(
constraints_lst,
lengths,
to_normalize,
device,
)[source]#

Batched version of create_conditions_from_constraints.

Supports either one shared constraint list for all batch elements, or a per-sample list of constraint lists.

Kimodo motion representation (<skel>_kimodo, formerly *_smooth_root).

Per-frame features relative to a smoothed root trajectory: smooth root position, global root heading (cos/sin), per-joint local positions (pelvis-origin plus the hips offset from the smooth root), global joint rotations as cont6d, per-joint velocities, and foot contacts — see the FeatureLayout in KimodoMotionRep.__init__. __call__ builds features from local rotations + root trajectory via FK; inverse reconstructs posed joints; create_conditions maps constraint sets onto the feature blocks for the denoiser. The root-local channels (root rot-vel / xz-vel / y) support the canonicalized local-root form used in training.

class kimodo.motion_rep.reps.kimodo_motionrep.KimodoMotionRep(
skeleton,
fps,
stats_path=None,
stats=None,
name=None,
**kwargs,
)[source]#

Bases: MotionRepBase

Global root / global joints rotations representation, relative to a smooth root.

__init__(
skeleton,
fps,
stats_path=None,
stats=None,
name=None,
**kwargs,
)[source]#

Initialize feature slicing metadata and optional normalization stats.

rotate(features, angle)[source]#

Rotate root/joint positional and rotational features by heading.

translate_2d(features, translation_2d)[source]#

Translate smooth root planar position by (dx, dz).

inverse(
features,
is_normalized,
posed_joints_from='rotations',
return_numpy=False,
return_all=False,
need_local_rots=True,
)[source]#

Decode smooth-root features into motion tensors.

return_all adds an all_positions dict with the joints decoded from the position and rotation blocks ({"positions": ..., "rotations": ...}). need_local_rots=False skips the global->local conversion (local_rot_mats is then None in the output) — the training losses only consume positions / global rotations.

create_conditions(
index_dict,
data_dict,
length,
to_normalize,
device,
)[source]#

Build sparse conditioning tensors for smooth-root representation.

Returns:

(observed_motion, motion_mask) where motion_mask is bool and unmasked cells of observed_motion keep whatever normalize produced from the zero initialization. This deliberately differs from ArdyMotionRep.create_conditions (float mask, unmasked cells zeroed) — callers are contract-specific.

TMR motion representation: global root, global joints, velocities, and foot contacts.

class kimodo.motion_rep.reps.tmr_motionrep.TMRMotionRep(skeleton, fps, stats_path=None, name=None)[source]#

Bases: MotionRepBase

Motion representation with global root and local joint positions.

The local joint positions are rotation invariant (they all face z+)

Feature layout: - root position (x, y, z) - root heading as (cos(theta), sin(theta)) - local joint positions (root and rotation removed) - local joint velocities (rotation removed) - binary foot contacts

__init__(skeleton, fps, stats_path=None, name=None)[source]#

Initialize feature slicing metadata and optional normalization stats.

rotate(features, angle)[source]#

Rotate all spatial features by a heading delta (radians).

translate_2d(features, translation_2d)[source]#

Translate root planar position by (dx, dz).

inverse(
features,
is_normalized,
posed_joints_from='positions',
return_numpy=False,
)[source]#

Decode features back to a motion dictionary.

Parameters:
  • features – Feature tensor [B, T, D].

  • is_normalized – Whether input features are normalized.

  • posed_joints_from – Must be "positions" for this representation.

  • return_numpy – Whether to convert tensors to numpy arrays.

Returns:

Dictionary containing reconstructed positions and auxiliary data.

Utilities#

Foot contact detection from joint positions and velocities.

kimodo.motion_rep.feet.foot_detect_from_pos_and_vel(
positions,
velocity,
skeleton,
vel_thres,
height_thresh,
)[source]#

Compute foot contact labels using heuristics combining joint height and velocities.

Parameters:
  • positions (torch.Tensor) – [X, T, J, 3] global joint positions

  • velocity (torch.Tensor) – [X, T, J, 3] velocities (already padded correctly), already multiplied by 1 / dt

  • vel_thres (float) – threshold for joint velocity

  • height_thresh (float) – threshold for joint height

Returns:

[X, T, 4] contact labels for left and right foot joints (heel/toe order follows the skeleton joint index definition), where 1 denotes contact.

Return type:

torch.Tensor

Feature normalization statistics (mean/std) for motion representations.

class kimodo.motion_rep.stats.Stats(folder=None, load=True, eps=1e-05)[source]#

Bases: <Mock object at 0x7c562016aa70>[]

Utility module for feature normalization statistics.

Normalization follows: (data - mean) / sqrt(std**2 + eps)

__init__(folder=None, load=True, eps=1e-05)[source]#
sliced(indices)[source]#

Return a new Stats object containing selected feature indices.

load()[source]#

Load mean.npy and std.npy from self.folder.

register_from_tensors(mean, std)[source]#

Register mean/std tensors as non-persistent buffers.

normalize(data)[source]#

Normalize data using the stored statistics.

unnormalize(data)[source]#

Undo normalization using the stored statistics.

is_loaded()[source]#

Return whether statistics are currently available.

get_dim()[source]#

Return feature dimensionality.

save(folder=None, mean=None, std=None)[source]#

Save statistics to folder as mean.npy and std.npy.

Smooth root trajectory: ADMM-based smoother with margin constraints and get_smooth_root_pos helper.

class kimodo.motion_rep.smooth_root.TrajectorySmoother(
margins,
pos_weight=0.0,
loop=False,
admm_iters=100,
alpha_overrelax=1.0,
circle_project=False,
)[source]#

Bases: object

Modify trajectories to hit target values while respecting soft constraints.

This smoother keeps the trajectory close to the original positions while minimizing accelerations. Targets are enforced at specified frames via soft constraints.

__init__(
margins,
pos_weight=0.0,
loop=False,
admm_iters=100,
alpha_overrelax=1.0,
circle_project=False,
)[source]#

Initialize the TrajectorySmoother.

Parameters:
  • margins – Array of margin values for each frame. margins[i] < 0: unconstrained margins[i] == 0: pinned on this frame margins[i] > 0: can deviate within the margin

  • pos_weight – Weight for position preservation

  • loop – Whether the trajectory should loop

  • admm_iters – Number of ADMM iterations

smooth(targets, x0)[source]#

Interpolate between reference positions while satisfying constraints.

Parameters:
  • observations – Target positions for constrained frames (numpy array)

  • ref_positions – Reference positions defining original shape (numpy array)

Returns:

Interpolated positions (numpy array)

x_update(x, z, u, x_t)[source]#

Update x in the ADMM iteration.

z_update(z, x, z_t, u)[source]#

Update z in the ADMM iteration using vectorized operations.

u_update(u, x, z)[source]#

Update u in the ADMM iteration using vectorized operations.

kimodo.motion_rep.smooth_root.smooth_signal(
x,
margins,
pos_weight=0,
alpha_overrelax=1.8,
admm_iters=500,
circle_project=False,
)[source]#

Multigrid trajectory smoothing with margin constraints.

Parameters:
  • x – Input trajectory [T, D] as a NumPy array.

  • margins – Allowed radius around each target frame [T].

  • pos_weight – Weight for staying close to the original signal.

  • alpha_overrelax – ADMM over-relaxation coefficient.

  • admm_iters – ADMM iterations per multigrid level.

  • circle_project – If True, project each vector to the unit sphere.

Returns:

Smoothed trajectory of shape [T, D].

kimodo.motion_rep.smooth_root.get_smooth_root_pos(hip_translations)[source]#

Smooth root trajectory in the ground plane while preserving height.

Parameters:

hip_translations – Root translations [B, T, 3].

Returns:

Smoothed root translations [B, T, 3] where x/z are smoothed and y remains unchanged.