Skip to main content

monomech

CI Docs PyPI Python

monomech is a notebook-first Python library for single-camera biomechanics. It helps you move from video or marker data into inspectable pose results, OpenSim-ready TRC files, inverse kinematics, inverse dynamics, and analysis tables without hiding the intermediate steps.

Full documentation: chags1313.github.io/monomech

Why Use It

  • Start from a normal video or an existing TRC file.
  • Export readable CSV and OpenSim-compatible TRC files.
  • Run pose estimation, marker cleanup, scaling, inverse kinematics, and inverse dynamics as separate inspectable steps.
  • Create OpenSim external loads from measured force data, arrays, carried loads, or estimated ground reaction forces.
  • Export IK-driven OpenSim animations to a single portable GLB file.
  • Review GLB meshes, markers, external-force arrows, IK traces, and ID traces in a Three.js HTML viewer.
  • Keep OpenSim preflight checks on by default so NaNs and isolated gaps are fixed before IK and ID runs.
  • Import the base package without installing heavy optional video or OpenSim dependencies.

Install

python -m pip install monomech

Choose extras only when you need them:

Workflow Install command
Video pose estimation python -m pip install "monomech[pose]"
OpenSim Python bindings python -m pip install "monomech[opensim]"
OpenSim animation export python -m pip install "monomech[animation]"
Notebooks and plots python -m pip install "monomech[notebook]"
Everything optional python -m pip install "monomech[all]"

monomech supports Python 3.10 through 3.12.

Quick Start: Video To TRC

from pathlib import Path
import monomech as mm

video_path = Path("data/subject01.mp4")
output_dir = Path("outputs/subject01")
output_dir.mkdir(parents=True, exist_ok=True)

pose3d_global = mm.estimate_pose(video_path, root_centered=False, floored=True)
pose3d_global = mm.gap_fill(mm.smooth(pose3d_global))

pose3d_global.to_csv(output_dir / "subject01_global.csv")
pose3d_global.to_trc(output_dir / "subject01_global.trc")

Or run the common video export path in one call:

run = mm.video_to_trc(video_path, output_dir=output_dir)

print(run.csv_paths)
print(run.trc_path)

Notebook-First Workflow

The high-level API is designed to read like the analysis steps in a notebook:

import monomech as mm

pose = mm.estimate_pose(
    "data/curl.mp4",
    root_centered=False,
    floored=True,
)

pose = mm.smooth(pose, cutoff_hz=6.0)
pose = mm.gap_fill(pose, max_gap_frames=12)

pose.vis_2d(frame=100)
pose.vis_3d(frame=100)

scaled_model = mm.run_scaling(pose, model="pose", output_dir="outputs/curl/scale")
ik = mm.run_ik(scaled_model, output_dir="outputs/curl/ik")

dumbbell = mm.load(type="carried", body="hand_r", mass_kg=10.0)
grf = mm.estimate_grf(pose, body_mass_kg=82.0)
forces = mm.external_forces(loads=[dumbbell, *grf])

id_result = mm.run_id(
    ik=ik,
    external_forces=forces,
    output_dir="outputs/curl/id",
)

ik.plot()
id_result.plot()

animation = mm.animate(
    ik=ik,
    id=id_result,
    external_loads_path=id_result.metadata["external_loads_mot_path"],
    output_dir="outputs/curl/visualizer",
    mode="balanced",
)
animation.show()

Carried and constant loads created without start_time and end_time are applied over the full IK trial. Use explicit times only for loads that turn on and off during the movement.

For batch scripts, use the one-call aliases:

result = mm.video_pipeline(
    "data/curl.mp4",
    model_path=mm.get_builtin_osim_model("pose"),
    output_dir="outputs/curl",
)

result.display()

Full Pipeline: Video To Inverse Dynamics

import monomech as mm

result = mm.video_to_inverse_dynamics(
    "data/subject01.mp4",
    model_path="models/subject01_scaled.osim",
    output_dir="outputs/subject01",
    body_mass_kg=75.0,
)

print(result.trc_path)
print(result.ik.path)
print(result.id.path)
print(result.visualizer.html_path)
result.display()

If you already have marker data in a TRC file, start at OpenSim:

result = mm.trc_to_inverse_dynamics(
    "outputs/subject01/subject01.trc",
    model_path="models/subject01_scaled.osim",
    output_dir="outputs/subject01/opensim",
    external_forces=None,
)

print(result.ik.path)
print(result.id.path)

Export the IK and ID run to one portable animation file:

animation = mm.save_opensim_animation(
    osim_path="models/subject01_scaled.osim",
    mot_path=result.ik.path,
    id_path=result.id.path,
    out_glb_path="outputs/subject01/animation/subject01_ik_id.glb",
    stride=2,
    decimate_target_reduction=0.35,
)

print(animation.glb_path)

Create a fast notebook-friendly Three.js dashboard with OpenSim body proxies, marker fallback, force arrows, IK plots, and ID plots:

viewer = mm.animate(
    ik=result.ik,
    id=result.id,
    model="models/subject01_scaled.osim",
    output_dir="outputs/subject01/visualizer",
    external_loads_path=result.id.metadata["external_loads_mot_path"],
    render="fast",
)
viewer.show()

The fast dashboard is a standalone HTML file, so it works in notebooks, local browsers, and GitHub Pages without waiting for GLB export. It controls lightweight body proxy meshes from OpenSim body transforms. When you need full anatomical surface meshes, use render="glb" or call mm.save_opensim_glb(...); the dashboard will reference the sibling GLB by default. Pass embed_glb=True only when you need one self-contained HTML file. The online visualizer starts empty and includes an Upload GLB control, which lets a reader drag in their own exported model without sending the file anywhere.

For a carried object plus estimated ground-reaction forces:

dumbbell = mm.external.carried_load(
    mass_kg=12.5,
    applied_to_body="radius_r",
    point=(0.0, -0.2, 0.0),
    name="right_dumbbell",
)

result = mm.video_to_inverse_dynamics(
    "data/curl.mp4",
    model_path=mm.get_builtin_osim_model("pose"),
    output_dir="outputs/curl",
    body_mass_kg=82.0,
    external_forces=mm.external.with_estimated_grf(dumbbell),
)

The GitHub Pages site includes an online GLB visualizer for quick review: chags1313.github.io/monomech/visualizer/.

Geometry note: the default full-body geometry is packaged with monomech, so most users do not need to pass geom_dir. Pass geom_dir only when using a different OpenSim model or custom mesh folder. If your model came from a macOS-created zip, avoid the __MACOSX folder because it usually contains only tiny ._*.vtp metadata files, not usable meshes.

For measured force plates, build an external-load spec from your force table:

right_grf = mm.external.from_csv(
    "data/right_force_plate.csv",
    applied_to_body="calcn_r",
    force_columns=("Fx", "Fy", "Fz"),
    point_columns=("Px", "Py", "Pz"),
    torque_columns=("Mx", "My", "Mz"),
    time_column="time",
    name="right_grf",
)

OpenSim Reliability Defaults

OpenSim is strict about missing or non-finite values. The OpenSim helpers preflight inputs by default:

  • TRC marker gaps are interpolated before scale and IK.
  • IK coordinate NaNs are interpolated before inverse dynamics.
  • External-load data is resampled to IK time and non-finite force values are filled with zero.
  • Preflight reports and generated paths are stored in result metadata.
print(ik.metadata["preflight"])
print(id_result.metadata["coordinate_preflight"])

Example Notebooks

The examples/ folder includes ready-to-edit notebooks:

Documentation

Development

python -m pip install -e ".[dev]"
python -m pytest tests
mkdocs build --strict
python -m build

Run a real video smoke test:

python examples/run_video_smoke.py "path/to/video.mp4" --output-dir outputs/smoke

Add --opensim when OpenSim-compatible bindings are installed.

Publishing

GitHub Actions builds distributions on every push to main. PyPI publishing goes directly to PyPI through trusted publishing and is triggered by version tags such as:

git tag v0.15.17
git push origin v0.15.17

The publish workflow can also be run manually from GitHub Actions with the publish input set to true.

License

See LICENSE.

Release files for monomech 0.15.24

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for monomech 0.15.24
File Size Uploaded
monomech-0.15.24.tar.gz 29.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for monomech 0.15.24
File Interpreter ABI Platform
monomech-0.15.24-py3-none-any.whl Python 3 none any Details

Total release size: 60.1 MB

Release files / monomech-0.15.24.tar.gz

Download URL monomech-0.15.24.tar.gz
Size 29.9 MB
Tags Source
SHA-256 checksum
How to use checksums
3227c4d80b8a794971fbe9124533e070dccef13573245f3da85f892640fdaecb
BLAKE2b-256 checksum
How to use checksums
3d77a0308d80edff443f09c16c11a080f4850716325c9268b6038d81cb73ca4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log

Release files / monomech-0.15.24-py3-none-any.whl

Download URL monomech-0.15.24-py3-none-any.whl
Size 30.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
492c44aa9ddea961cce21cf73cbedc63395fabc43d37c16d82bda28befe1dd58
BLAKE2b-256 checksum
How to use checksums
3a8a4ec89b6856771920a6af2635a86281728fe2f44b618d8a0dc52f30c72284
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page