Multi-backend parametric body models (SMPL, SMPLX, FLAME, SKEL, ANNY, MHR) for NumPy, PyTorch, and JAX
Project description
body-models
A unified library for parametric human body models.
Provides a shared interface across SMPL, SMPL-X, SKEL, FLAME, ANNY, and MHR body models with PyTorch, NumPy, and JAX backends.
Features
- Multi-backend: PyTorch, NumPy, and JAX
- Disentangled outputs: separate
forward_vertices(mesh) andforward_skeleton(joint transforms) - Mesh simplification: lower-resolution forward pass via
simplifyconstructor argument - Vertex subsets: compute only specific vertices via
vertex_indicesargument - Rotation representations: axis-angle, quaternion, 6D, rotation matrix, and projected matrix (
rotation_typeconstructor argument)
Installation
pip install body-models
Or with uv:
uv add body-models
Optional backends
PyTorch and JAX are optional dependencies. Install them for the corresponding backends:
# For PyTorch backend
pip install body-models[torch]
# For JAX backend
pip install body-models[jax]
Note: NumPy/JAX backends can load MHR torch checkpoints without installing PyTorch.
Model Setup
Auto-download models
ANNY and MHR models are automatically downloaded on first use:
from body_models.anny.torch import ANNY
from body_models.mhr.torch import MHR
model = ANNY() # Downloads automatically (CC0 license)
model = MHR() # Downloads automatically (Apache 2.0)
Registration-required models
SMPL, SMPL-X, SKEL, and FLAME require registration. Download from:
- SMPL: https://smpl.is.tue.mpg.de/
- SMPL-X: https://smpl-x.is.tue.mpg.de/
- SKEL: https://skel.is.tue.mpg.de/
- FLAME: https://flame.is.tue.mpg.de/
SMPL .pkl and .npz files are both supported directly. Configure the paths (per gender):
body-models set smpl-neutral /path/to/SMPL_NEUTRAL.pkl
body-models set smpl-male /path/to/SMPL_MALE.pkl
body-models set smpl-female /path/to/SMPL_FEMALE.pkl
body-models set smplx-neutral /path/to/SMPLX_NEUTRAL.npz
body-models set skel /path/to/skel
body-models set flame /path/to/flame
Or pass file paths directly:
from body_models.smpl.torch import SMPL
# Direct file path (no gender needed)
model = SMPL(model_path="/path/to/SMPL_NEUTRAL.pkl")
# From config using gender
model = SMPL(gender="neutral") # Uses smpl-neutral config key
Configuration
View current settings:
$ body-models
Config file: /path/to/config.toml # Platform-dependent location
Current settings:
smpl-male: /data/models/smpl/SMPL_MALE.pkl
smpl-female: /data/models/smpl/SMPL_FEMALE.pkl
smpl-neutral: /data/models/smpl/SMPL_NEUTRAL.pkl
smplx-male: (not set)
smplx-female: (not set)
smplx-neutral: (not set)
skel: (not set)
flame: (not set)
anny: (not set)
mhr: (not set)
Manage paths:
body-models set <model> <path> # Set model path
body-models unset <model> # Remove from config
Quick Start
# Import from specific backend (torch, numpy, or jax)
from body_models.smplx.torch import SMPLX
# Load model from config
model = SMPLX(gender="neutral") # Uses smplx-neutral config key
# Or load from direct file path
model = SMPLX(model_path="/path/to/SMPLX_NEUTRAL.npz")
# Get default parameters
params = model.get_rest_pose(batch_size=4)
# Generate mesh vertices
vertices = model.forward_vertices(**params) # [4, V, 3]
# Get skeleton transforms
skeleton = model.forward_skeleton(**params) # [4, J, 4, 4]
Available backends:
body_models.<model>.torch- PyTorch (differentiable)body_models.<model>.numpy- NumPybody_models.<model>.jax- JAX/Flax (differentiable)
Common Interface
All models inherit from BodyModel and share these properties:
| Property | Type | Description |
|---|---|---|
num_joints |
int |
Number of skeleton joints |
num_vertices |
int |
Number of mesh vertices |
joint_names |
list[str] |
Joint names |
faces |
[F, 3] |
Mesh face indices |
skin_weights |
[V, J] |
Skinning weights |
rest_vertices |
[V, 3] |
Vertices in rest pose |
Common Methods
# Get zero-initialized parameters (model-specific keys)
params = model.get_rest_pose(batch_size=1)
# Compute mesh vertices [B, V, 3] in meters
vertices = model.forward_vertices(**params)
# Compute joint transforms [B, J, 4, 4] in meters
transforms = model.forward_skeleton(**params)
Mesh Simplification
All models support mesh simplification via the simplify constructor argument:
# Reduce face count by half (2x simplification)
model = SMPL(gender="neutral", simplify=2.0)
# Reduce to ~1/4 of original faces
model = SMPLX(gender="neutral", simplify=4.0)
The simplify parameter is a divisor for the face count. Default is 1.0 (no simplification). Skinning weights and blend shapes are automatically mapped to the simplified mesh.
Vertex Subsets
All mesh-based models support computing only specific vertices:
# Only compute vertices 0, 100, 200
vertices = model.forward_vertices(**params, vertex_indices=[0, 100, 200])
# Returns [B, 3, 3] instead of [B, V, 3]
This avoids computing the full mesh when you only need a few vertices (e.g. for landmark loss).
Rotation Representations
SMPL, SMPL-X, FLAME, and ANNY support multiple rotation representations via the rotation_type constructor argument:
model = SMPL(gender="neutral", rotation_type="sixd") # Use 6D rotations
Supported types:
| Type | Shape per joint | Description |
|---|---|---|
"axis_angle" |
[3] |
Axis-angle (default) |
"quat" |
[4] |
Quaternion (wxyz convention) |
"sixd" |
[6] |
6D continuous representation |
"rotmat" |
[3, 3] |
Rotation matrix (assumed SO(3)) |
"matrix" |
[3, 3] |
General 3x3 matrix (SVD-projected to SO(3)) |
The "matrix" type is useful when optimizing rotations without constraints -- inputs are projected to the nearest valid rotation matrix via SVD. The "rotmat" type assumes inputs are already valid rotation matrices and skips the projection.
Supported Models
SMPL
The original parametric body model with 6890 vertices and 24 joints.
from body_models.smpl.torch import SMPL # or .numpy, .jax
model = SMPL(gender="neutral") # "neutral", "male", or "female"
vertices = model.forward_vertices(
shape, # [B, 10] body shape betas
body_pose, # [B, 23, 3] axis-angle per joint
pelvis_rotation, # [B, 3] root joint rotation (optional)
global_rotation, # [B, 3] post-transform rotation (optional)
global_translation, # [B, 3] translation (optional)
)
Conversion functions for working with the official smplx library format:
from body_models import smpl
# Convert flat tensors to API format
args = smpl.from_native_args(shape, body_pose, pelvis_rotation, global_translation)
vertices = model.forward_vertices(**args)
transforms = model.forward_skeleton(**args)
# Convert outputs back to native format
result = smpl.to_native_outputs(vertices, transforms)
SMPL-X
Expressive body model with articulated hands and facial expressions.
from body_models.smplx.torch import SMPLX # or .numpy, .jax
model = SMPLX(
gender="neutral", # "neutral", "male", or "female"
flat_hand_mean=False, # Flat hands as mean pose
)
vertices = model.forward_vertices(
shape, # [B, 10] body shape betas
body_pose, # [B, 21, 3] axis-angle per body joint
hand_pose, # [B, 30, 3] axis-angle (left 15 + right 15)
head_pose, # [B, 3, 3] jaw + left eye + right eye
expression, # [B, 10] facial expression (optional)
pelvis_rotation, # [B, 3] root joint rotation (optional)
global_rotation, # [B, 3] post-transform rotation (optional)
global_translation, # [B, 3] translation (optional)
)
Conversion functions for working with the official smplx library format:
from body_models import smplx
# Convert flat tensors to API format
args = smplx.from_native_args(shape, expression, body_pose, hand_pose, head_pose,
pelvis_rotation, global_translation)
vertices = model.forward_vertices(**args)
transforms = model.forward_skeleton(**args)
# Convert outputs back to native format
result = smplx.to_native_outputs(vertices, transforms)
SKEL
Anatomically realistic skeletal articulation based on OpenSim. Only "male" and "female" genders are supported (no "neutral").
from body_models.skel.torch import SKEL # or .numpy, .jax
model = SKEL(gender="male") # "male" or "female" (no neutral)
vertices = model.forward_vertices(
shape, # [B, 10] body shape betas
pose, # [B, 46] anatomically constrained DOFs
global_rotation, # [B, 3] axis-angle (optional)
global_translation, # [B, 3] (optional)
)
FLAME
FLAME (Faces Learned with an Articulated Model and Expressions) head model.
from body_models.flame.torch import FLAME # or .numpy, .jax
model = FLAME() # Uses configured path
vertices = model.forward_vertices(
shape, # [B, 300] shape betas (can use fewer)
expression, # [B, 100] expression coefficients (optional)
pose, # [B, 4, 3] axis-angle for neck, jaw, left_eye, right_eye (optional)
head_rotation, # [B, 3] root joint rotation (optional)
global_rotation, # [B, 3] post-transform rotation (optional)
global_translation, # [B, 3] translation (optional)
)
Conversion functions for working with the official FLAME/smplx library format:
from body_models import flame
# Convert native args to API format
args = flame.from_native_args(shape, expression, pose, head_rotation, global_rotation, global_translation)
vertices = model.forward_vertices(**args)
transforms = model.forward_skeleton(**args)
# Convert outputs back to native format
result = flame.to_native_outputs(vertices, transforms)
ANNY
Phenotype-based body model with intuitive shape parameters.
from body_models.anny.torch import ANNY # or .numpy, .jax
model = ANNY(
rig="default", # "default", "default_no_toes", "cmu_mb", "game_engine", "mixamo"
topology="default", # "default" or "makehuman"
all_phenotypes=False, # Include race/cupsize/firmness
extrapolate_phenotypes=False, # Allow values outside [0, 1]
)
vertices = model.forward_vertices(
gender, # [B] in [0, 1] (0=male, 1=female)
age, # [B] in [0, 1]
muscle, # [B] in [0, 1]
weight, # [B] in [0, 1]
height, # [B] in [0, 1]
proportions, # [B] in [0, 1]
pose, # [B, J, 3] axis-angle per joint
global_rotation, # [B, 3] axis-angle (optional)
global_translation, # [B, 3] (optional)
)
MHR
Meta Human Renderer with neural pose correctives.
from body_models.mhr.torch import MHR # or .numpy, .jax
model = MHR(lod=1) # Level of detail
vertices = model.forward_vertices(
shape, # [B, 45] identity blendshapes
pose, # [B, 204] pose parameters
expression, # [B, 72] facial expression (optional)
global_rotation, # [B, 3] axis-angle (optional)
global_translation, # [B, 3] (optional)
)
Conversion functions for working with the original MHR format (cm units):
from body_models import mhr
# Convert native args (shape, expression, pose order) to API format
args = mhr.from_native_args(shape, expression, pose)
vertices = model.forward_vertices(**args)
transforms = model.forward_skeleton(**args)
# Convert outputs to native format (cm units, skeleton state [t, q, s])
result = mhr.to_native_outputs(vertices, transforms)
Coordinate System
The unified API returns outputs in:
- Y-up coordinate system
- Meters as the unit
Use the to_native_outputs() conversion functions to get outputs in the original library conventions.
Development
uvx ruff format . # Format code
uvx ruff check . # Lint
uvx ty check # Type check
License
See individual model licenses for usage terms:
- SMPL: https://smpl.is.tue.mpg.de/
- SMPL-X: https://smpl-x.is.tue.mpg.de/
- SKEL: https://skel.is.tue.mpg.de/
- FLAME: https://flame.is.tue.mpg.de/
- ANNY: CC0 (MakeHuman data)
- MHR: Apache 2.0 (Meta Platforms, Inc.)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file body_models-0.8.0.tar.gz.
File metadata
- Download URL: body_models-0.8.0.tar.gz
- Upload date:
- Size: 65.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44e5503af14b5afb9864d15a531cba3e098230154677c0fb7672e16115272129
|
|
| MD5 |
0c6b95663230d3ca0c093f0ee31a8bb4
|
|
| BLAKE2b-256 |
07a700eaa04a0d1ab4a7703a780f1f582646943d680363dc476e0414a86d049b
|
File details
Details for the file body_models-0.8.0-py3-none-any.whl.
File metadata
- Download URL: body_models-0.8.0-py3-none-any.whl
- Upload date:
- Size: 99.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38a99c41ecc92e7ad512fa7c3a06af2d1cfd71c6a98a77ee28d8fac6ba13efb2
|
|
| MD5 |
d7159a51b5db56b4e4420b69e8dd36f9
|
|
| BLAKE2b-256 |
f2a3140f266aa77aa2645e19c0ba129fc4990a08f6f16324b7cba410c12bcb8c
|