Loading repository data…
Loading repository data…
UPC-ViRVIG / repository
A Python library for working with motion data in numpy or PyTorch
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
PyMotion is a Python library that provides various functions for manipulating and processing motion data in NumPy or PyTorch. It is designed to facilitate the development of neural networks for character animation.
Some features of PyMotion are:
[Optional] Install PyTorch using Pip as instructed in their webpage.
Install PyMotion:
pip install upc-pymotion
pip install upc-pymotion[viewer]
The examples below are small API snippets. Larger, runnable examples live in examples/; each example has its own README and optional dependencies so research-specific packages are not installed with PyMotion itself.
examples/bones_seed_soma/ loads BONES-SEED SOMA BVH files with PyMotion and runs them through SOMA.import numpy as np
from pymotion.io.bvh import BVH
bvh = BVH()
bvh.load("test.bvh")
print(bvh.data["names"])
# Example Output: ['Hips', 'LeftHip', 'LeftKnee', 'LeftAnkle', 'LeftToe', 'RightHip', 'RightKnee', 'RightAnkle', 'RightToe', 'Chest', 'Chest3', 'Chest4', 'Neck', 'Head', 'LeftCollar', 'LeftShoulder', 'LeftElbow', 'LeftWrist', 'RightCollar', 'RightShoulder', 'RightElbow', 'RightWrist']
# Move root joint to (0, 0, 0)
local_rotations, local_positions, parents, offsets, end_sites, end_sites_parents = bvh.get_data()
local_positions[:, 0, :] = np.zeros((local_positions.shape[0], 3))
bvh.set_data(local_rotations, local_positions)
# Scale the skeleton
bvh.set_scale(0.75)
bvh.save("test_out.bvh")
NumPy
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton import fk
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, end_sites, end_sites_parents = bvh.get_data()
global_positions = local_positions[:, 0, :] # root joint
pos, rotmats = fk(local_rotations, global_positions, offsets, parents)
PyTorch
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton_torch import fk
import torch
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, end_sites, end_sites_parents = bvh.get_data()
global_positions = local_positions[:, 0, :] # root joint
pos, rotmats = fk(
torch.from_numpy(local_rotations),
torch.from_numpy(global_positions),
torch.from_numpy(offsets),
torch.from_numpy(parents),
)
NumPy
import pymotion.rotations.quat as quat
import numpy as np
angles = np.array([np.pi / 2, np.pi, np.pi / 4])[..., np.newaxis]
# angles.shape = [3, 1]
axes = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# axes.shape = [3, 3]
q = quat.from_angle_axis(angles, axes)
rotmats = quat.to_matrix(q)
euler = quat.to_euler(q, np.array([["x", "y", "z"], ["z", "y", "x"], ["y", "z", "x"]]))
euler_degrees = np.degrees(euler)
scaled_axis = quat.to_scaled_angle_axis(q)
PyTorch
import pymotion.rotations.quat_torch as quat
import numpy as np
import torch
angles = torch.Tensor([torch.pi / 2, torch.pi, torch.pi / 4]).unsqueeze(-1)
# angles.shape = [3, 1]
axes = torch.Tensor([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
# axes.shape = [3, 3]
q = quat.from_angle_axis(angles, axes)
rotmats = quat.to_matrix(q)
euler = quat.to_euler(q, np.array([["x", "y", "z"], ["z", "y", "x"], ["y", "z", "x"]]))
euler_degrees = torch.rad2deg(euler)
scaled_axis = quat.to_scaled_angle_axis(q)
NumPy
from pymotion.io.bvh import BVH
import pymotion.ops.skeleton as sk
import numpy as np
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, end_sites, end_sites_parents = bvh.get_data()
root_dual_quats = sk.to_root_dual_quat(
local_rotations, local_positions[:, 0, :], parents, offsets
)
local_translations, local_rotations = sk.from_root_dual_quat(root_dual_quats, parents)
global_positions = local_translations[:, 0, :]
offsets = local_translations.copy()
offsets[:, 0, :] = np.zeros((offsets.shape[0], 3))
PyTorch
from pymotion.io.bvh import BVH
import pymotion.ops.skeleton_torch as sk
import torch
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, end_sites, end_sites_parents = bvh.get_data()
root_dual_quats = sk.to_root_dual_quat(
torch.from_numpy(local_rotations),
torch.from_numpy(local_positions[:, 0, :]),
torch.from_numpy(parents),
torch.from_numpy(offsets),
)
local_translations, local_rotations = sk.from_root_dual_quat(root_dual_quats, parents)
global_positions = local_translations[:, 0, :]
offsets = local_translations.clone()
offsets[:, 0, :] = torch.zeros((offsets.shape[0], 3))
NumPy
from pymotion.io.bvh import BVH
import pymotion.rotations.ortho6d as sixd
bvh = BVH()
bvh.load("test.bvh")
local_rotations, _, _, _, _, _ = bvh.get_data()
continuous = sixd.from_quat(local_rotations)
local_rotations = sixd.to_quat(continuous)
PyTorch
from pymotion.io.bvh import BVH
import pymotion.rotations.ortho6d_torch as sixd
import torch
bvh = BVH()
bvh.load("test.bvh")
local_rotations, _, _, _, _, _ = bvh.get_data()
continuous = sixd.from_quat(torch.from_numpy(local_rotations))
local_rotations = sixd.to_quat(continuous)
NumPy
import numpy as np
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton import fk
from pymotion.ops.skeleton import from_root_positions
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, _, _ = bvh.get_data()
pos, _ = fk(local_rotations, np.zeros((local_positions.shape[0], 3)), offsets, parents)
pred_rots = from_root_positions(pos, parents, offsets)
bvh.set_data(pred_rots, local_positions)
bvh.save("test_out.bvh") # joint positions should be similar as test.bvh
PyTorch
import torch
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton_torch import fk
from pymotion.ops.skeleton_torch import from_root_positions
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, _, _ = bvh.get_data()
offsets = torch.from_numpy(offsets)
parents = torch.from_numpy(parents)
pos, _ = fk(
torch.from_numpy(local_rotations),
torch.zeros((local_positions.shape[0], 3)),
offsets,
parents,
)
pred_rots = from_root_positions(pos, parents, offsets)
bvh.set_data(pred_rots.numpy(), local_positions)
bvh.save("test_out.bvh") # joint positions should be similar as test.bvh
NumPy
import numpy as np
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton import mirror
bvh = BVH()
bvh.load("test.bvh")
names = bvh.data["names"].tolist()
print(names)
# ['Hips', 'Chest', 'Chest2', 'Chest3', 'Chest4', 'Neck', 'Head', 'RightCollar', 'RightShoulder',
# 'RightElbow', 'RightWrist', 'LeftCollar', 'LeftShoulder', 'LeftElbow', 'LeftWrist', 'RightHip',
# 'RightKnee', 'RightAnkle', 'RightToe', 'LeftHip', 'LeftKnee', 'LeftAnkle', 'LeftToe']
joints_mapping = np.array(
[
(
names.index("Left" + n[5:])
if n.startswith("Right")
else (names.index("Right" + n[4:]) if n.startswith("Left") else names.index(n))
)
for n in names
]
)
local_rotations, local_positions, parents, offsets, end_sites, _ = bvh.get_data()
mirrored_local_rots, mirrored_global_pos, mirrored_offsets, _ = mirror(
local_rotations,
local_positions[:, 0, :], # global position of the root joint
parents,
offsets,
end_sites,
joints_mapping=joints_mapping, # joints_mapping is only required for mode="symmetry"
mode="symmetry", # other modes: "all" or "positions"
axis="X",
)
local_positions[:, 0, :] = mirrored_global_pos
bvh.set_data(mirrored_local_rots, local_positions)
# Uncomment when mode == "all"
# bvh.data["offsets"] = mirrored_offsets
bvh.save("test_mirrored.bvh")
PyTorch
import torch
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton_torch import mirror
bvh = BVH()
bvh.load("test.bvh")
names = bvh.data["names"].tolist()
print(names)
# ['Hips', 'Chest', 'Chest2', 'Chest3', 'Chest4', 'Neck', 'Head', 'RightCollar', 'RightShoulder',
# 'RightElbow', 'RightWrist', 'LeftCollar', 'LeftShoulder', 'LeftElbow', 'LeftWrist', 'RightHip',
# 'RightKnee', 'RightAnkle', 'RightToe', 'LeftHip', 'LeftKnee', 'LeftAnkle', 'LeftToe']
joints_mapping = torch.Tensor(
[
(
names.index("Left" + n[5:])
if n.startswith("Right")
else (names.index("Right" + n[4:]) if n.startswith("Left") else names.index(n))
)
for n in names
]
).to(torch.int32)
local_rotations, local_positions, parents, offsets, end_sites, _ = bvh.get_data()
mirrored_local_rots, mirrored_global_pos, mirrored_offsets, _ = mirror(
torch.from_numpy(local_rotations),
torch.from_numpy(local_positions[:, 0, :]), # global position of the root joint
torch.from_numpy(parents),
torch.from_numpy(offsets),
torch.from_numpy(end_sites),
joints_mapping=joints_mapping, # joints_mapping is only required for mode="symmetry"
mode="symmetry", # other modes: "all" or "positions"
axis="X",
)
local_positions[:, 0, :] = mirrored_global_pos.numpy()
bvh.set_data(mirrored_local_rots.numpy(), local_positions)
# Uncomment when mode == "all"
# bvh.data["offsets"] = mirrored_offsets.numpy()
bvh.save("test_mirrored.bvh")
from pymotion.render.viewer import Viewer
from pymotion.io.bvh import BVH
from pymotion.ops.skeleton import fk
bvh = BVH()
bvh.load("test.bvh")
local_rotations, local_positions, parents, offsets, _, _ = bvh.get_data()
global_positions = local_positions[:, 0, :] # root joint
pos, rotmats = fk(local_rotations, global_positions, offsets, parents)
viewer = Viewer(use_reloader=True, xy_size=5)
viewer.add_skeleton(pos, parents)
# add additional info using add_sphere(...) and/or add_line(...), examples:
# viewer.add_sphere(sphere_pos, color="green")
# view