monomech 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. monomech-0.1.0/LICENSE +21 -0
  2. monomech-0.1.0/MANIFEST.in +4 -0
  3. monomech-0.1.0/PKG-INFO +144 -0
  4. monomech-0.1.0/README.md +105 -0
  5. monomech-0.1.0/docs/api.md +17 -0
  6. monomech-0.1.0/docs/getting-started.md +34 -0
  7. monomech-0.1.0/docs/index.md +14 -0
  8. monomech-0.1.0/docs/notebooks.md +9 -0
  9. monomech-0.1.0/docs/packaging.md +26 -0
  10. monomech-0.1.0/examples/MonoMech_External_Forces.ipynb +42 -0
  11. monomech-0.1.0/examples/MonoMech_Getting_Started.ipynb +59 -0
  12. monomech-0.1.0/examples/assets/Mediapipe_Model.osim +6932 -0
  13. monomech-0.1.0/examples/assets/MovisionModel.fbx +0 -0
  14. monomech-0.1.0/examples/basic_pipeline.py +9 -0
  15. monomech-0.1.0/examples/forces_demo.py +10 -0
  16. monomech-0.1.0/mkdocs.yml +9 -0
  17. monomech-0.1.0/pyproject.toml +51 -0
  18. monomech-0.1.0/setup.cfg +4 -0
  19. monomech-0.1.0/src/monomech/__init__.py +21 -0
  20. monomech-0.1.0/src/monomech/_constants.py +42 -0
  21. monomech-0.1.0/src/monomech/assets/default_rig_map.yml +127 -0
  22. monomech-0.1.0/src/monomech/cli.py +54 -0
  23. monomech-0.1.0/src/monomech/config.py +57 -0
  24. monomech-0.1.0/src/monomech/exceptions.py +10 -0
  25. monomech-0.1.0/src/monomech/exports/__init__.py +4 -0
  26. monomech-0.1.0/src/monomech/exports/mot.py +27 -0
  27. monomech-0.1.0/src/monomech/exports/trc.py +82 -0
  28. monomech-0.1.0/src/monomech/forces.py +85 -0
  29. monomech-0.1.0/src/monomech/io/__init__.py +3 -0
  30. monomech-0.1.0/src/monomech/io/videos.py +10 -0
  31. monomech-0.1.0/src/monomech/opensim/__init__.py +12 -0
  32. monomech-0.1.0/src/monomech/opensim/common.py +16 -0
  33. monomech-0.1.0/src/monomech/opensim/id.py +161 -0
  34. monomech-0.1.0/src/monomech/opensim/ik.py +58 -0
  35. monomech-0.1.0/src/monomech/opensim/io.py +67 -0
  36. monomech-0.1.0/src/monomech/pipeline.py +155 -0
  37. monomech-0.1.0/src/monomech/pose/__init__.py +4 -0
  38. monomech-0.1.0/src/monomech/pose/mediapipe_backend.py +233 -0
  39. monomech-0.1.0/src/monomech/pose/pnp.py +118 -0
  40. monomech-0.1.0/src/monomech/pose/pose2d.py +10 -0
  41. monomech-0.1.0/src/monomech/pose/poseworld.py +76 -0
  42. monomech-0.1.0/src/monomech/results.py +93 -0
  43. monomech-0.1.0/src/monomech/utils.py +57 -0
  44. monomech-0.1.0/src/monomech/visualization/__init__.py +4 -0
  45. monomech-0.1.0/src/monomech/visualization/notebook.py +14 -0
  46. monomech-0.1.0/src/monomech/visualization/pose.py +184 -0
  47. monomech-0.1.0/src/monomech/visualization/rig.py +203 -0
  48. monomech-0.1.0/src/monomech.egg-info/PKG-INFO +144 -0
  49. monomech-0.1.0/src/monomech.egg-info/SOURCES.txt +53 -0
  50. monomech-0.1.0/src/monomech.egg-info/dependency_links.txt +1 -0
  51. monomech-0.1.0/src/monomech.egg-info/entry_points.txt +2 -0
  52. monomech-0.1.0/src/monomech.egg-info/requires.txt +22 -0
  53. monomech-0.1.0/src/monomech.egg-info/top_level.txt +1 -0
  54. monomech-0.1.0/tests/test_exports.py +42 -0
  55. monomech-0.1.0/tests/test_results.py +11 -0
monomech-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md LICENSE mkdocs.yml
2
+ recursive-include docs *.md
3
+ recursive-include src/monomech/assets *.yml
4
+ recursive-include examples *.ipynb *.py *.md *.fbx *.osim
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: monomech
3
+ Version: 0.1.0
4
+ Summary: MonoMech: single-camera biomechanics from video to kinematics and kinetics
5
+ Author: OpenAI for user
6
+ License: MIT
7
+ Keywords: biomechanics,mediapipe,opensim,pose estimation,single camera,kinematics,kinetics
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Topic :: Scientific/Engineering
15
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: numpy>=1.24
20
+ Requires-Dist: pandas>=2.0
21
+ Requires-Dist: opencv-python>=4.8
22
+ Requires-Dist: plotly>=5.20
23
+ Requires-Dist: jinja2>=3.1
24
+ Requires-Dist: pyyaml>=6.0
25
+ Requires-Dist: tqdm>=4.66
26
+ Requires-Dist: typing-extensions>=4.9
27
+ Provides-Extra: pose
28
+ Requires-Dist: mediapipe>=0.10.33; extra == "pose"
29
+ Provides-Extra: viz
30
+ Requires-Dist: ipython>=8.0; extra == "viz"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: nbformat>=5.10; extra == "dev"
34
+ Requires-Dist: build>=1.2; extra == "dev"
35
+ Requires-Dist: twine>=5.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.10; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # MonoMech
41
+
42
+ **MonoMech** is a single-camera-to-biomechanics Python library for turning one video path or a list of video paths into inspectable kinematics and kinetics.
43
+
44
+ It is designed to be:
45
+
46
+ - **modular**: each stage is callable on its own
47
+ - **notebook friendly**: every stage returns a dataframe-centric result object and optional HTML visualization
48
+ - **OpenSim aware**: exports `TRC`, `MOT`, `STO`, `CSV`, and builds inverse-kinematics / inverse-dynamics workflows
49
+ - **publishable**: ships with `pyproject.toml`, docs, tests, conda recipe, and example notebooks
50
+
51
+ ## Main ideas
52
+
53
+ ```python
54
+ from monomech import MonoMechPipeline, PipelineConfig, dumbbell_force
55
+
56
+ pipeline = MonoMechPipeline(
57
+ PipelineConfig(output_root="outputs")
58
+ )
59
+
60
+ trial = pipeline.run(
61
+ "subject01_squat.mp4",
62
+ model_path="examples/assets/Mediapipe_Model.osim",
63
+ fbx_path="examples/assets/MovisionModel.fbx",
64
+ external_forces=[
65
+ dumbbell_force(side="right", mass_kg=12.5, point_in_body=(0.0, -0.02, 0.0))
66
+ ],
67
+ )
68
+
69
+ trial.pose2d.inspect().head()
70
+ trial.poseworld.inspect().head()
71
+ trial.inverse_kinematics.inspect().head()
72
+ trial.inverse_dynamics.inspect().head()
73
+ trial.visualizations["pose_analysis"]
74
+ trial.visualizations["rig_viewer"]
75
+ ```
76
+
77
+ ## Stage-by-stage API
78
+
79
+ Each stage can also run on its own:
80
+
81
+ - `pose2d(video)` – normalized image-space landmarks
82
+ - `pose3d(video)` – MediaPipe world landmarks
83
+ - `poseworld(pose2d, pose3d)` – PnP + floor-stabilized world coordinates
84
+ - `inverse_kinematics(trc, model)`
85
+ - `inverse_dynamics(ik_mot, model, external_forces)`
86
+ - `external_forces([...])` – friendly force specs, including a dumbbell helper
87
+
88
+ ## Installation
89
+
90
+ ### Core package
91
+
92
+ ```bash
93
+ pip install monomech
94
+ ```
95
+
96
+ ### Pose extraction extra
97
+
98
+ ```bash
99
+ pip install "monomech[pose,viz]"
100
+ ```
101
+
102
+ ### OpenSim-enabled environment
103
+
104
+ OpenSim is intentionally treated as an **optional runtime** because it is typically distributed through conda rather than PyPI.
105
+
106
+ ```bash
107
+ conda install -c opensim-org opensim
108
+ pip install "monomech[pose,viz]"
109
+ ```
110
+
111
+ ## Files written by default
112
+
113
+ For each trial, MonoMech writes:
114
+
115
+ - `pose2d.csv`
116
+ - `pose3d.csv`
117
+ - `pose_confidence.csv`
118
+ - `poseworld.csv`
119
+ - `camera.csv`
120
+ - `poseworld.trc`
121
+ - `ik.mot` and `ik.csv` when IK is run
122
+ - `external_loads.mot` and `ExternalLoads.xml` when forces are added
123
+ - `id.sto` and `id.csv` when inverse dynamics is run
124
+ - `pose_analysis.html`
125
+ - `rig_viewer.html`
126
+
127
+ ## Notebook-friendly results
128
+
129
+ Each stage returns a `StageResult` with:
130
+
131
+ - `.dataframe`
132
+ - `.artifacts`
133
+ - `.metadata`
134
+ - `.inspect()`
135
+ - `.to_csv()`
136
+ - `_repr_html_()` for a quick preview in Jupyter
137
+
138
+ ## Caveats
139
+
140
+ - OpenSim availability differs by environment; IK/ID will raise a clean error if the `opensim` Python module is unavailable.
141
+ - The FBX viewer is configurable. A default rig mapping is included and can be overridden for your asset.
142
+ - Single-camera kinetics still depend on modeling assumptions. MonoMech makes those assumptions explicit in the metadata and exported files.
143
+
144
+ See the `docs/` folder and example notebooks for end-to-end usage.
@@ -0,0 +1,105 @@
1
+ # MonoMech
2
+
3
+ **MonoMech** is a single-camera-to-biomechanics Python library for turning one video path or a list of video paths into inspectable kinematics and kinetics.
4
+
5
+ It is designed to be:
6
+
7
+ - **modular**: each stage is callable on its own
8
+ - **notebook friendly**: every stage returns a dataframe-centric result object and optional HTML visualization
9
+ - **OpenSim aware**: exports `TRC`, `MOT`, `STO`, `CSV`, and builds inverse-kinematics / inverse-dynamics workflows
10
+ - **publishable**: ships with `pyproject.toml`, docs, tests, conda recipe, and example notebooks
11
+
12
+ ## Main ideas
13
+
14
+ ```python
15
+ from monomech import MonoMechPipeline, PipelineConfig, dumbbell_force
16
+
17
+ pipeline = MonoMechPipeline(
18
+ PipelineConfig(output_root="outputs")
19
+ )
20
+
21
+ trial = pipeline.run(
22
+ "subject01_squat.mp4",
23
+ model_path="examples/assets/Mediapipe_Model.osim",
24
+ fbx_path="examples/assets/MovisionModel.fbx",
25
+ external_forces=[
26
+ dumbbell_force(side="right", mass_kg=12.5, point_in_body=(0.0, -0.02, 0.0))
27
+ ],
28
+ )
29
+
30
+ trial.pose2d.inspect().head()
31
+ trial.poseworld.inspect().head()
32
+ trial.inverse_kinematics.inspect().head()
33
+ trial.inverse_dynamics.inspect().head()
34
+ trial.visualizations["pose_analysis"]
35
+ trial.visualizations["rig_viewer"]
36
+ ```
37
+
38
+ ## Stage-by-stage API
39
+
40
+ Each stage can also run on its own:
41
+
42
+ - `pose2d(video)` – normalized image-space landmarks
43
+ - `pose3d(video)` – MediaPipe world landmarks
44
+ - `poseworld(pose2d, pose3d)` – PnP + floor-stabilized world coordinates
45
+ - `inverse_kinematics(trc, model)`
46
+ - `inverse_dynamics(ik_mot, model, external_forces)`
47
+ - `external_forces([...])` – friendly force specs, including a dumbbell helper
48
+
49
+ ## Installation
50
+
51
+ ### Core package
52
+
53
+ ```bash
54
+ pip install monomech
55
+ ```
56
+
57
+ ### Pose extraction extra
58
+
59
+ ```bash
60
+ pip install "monomech[pose,viz]"
61
+ ```
62
+
63
+ ### OpenSim-enabled environment
64
+
65
+ OpenSim is intentionally treated as an **optional runtime** because it is typically distributed through conda rather than PyPI.
66
+
67
+ ```bash
68
+ conda install -c opensim-org opensim
69
+ pip install "monomech[pose,viz]"
70
+ ```
71
+
72
+ ## Files written by default
73
+
74
+ For each trial, MonoMech writes:
75
+
76
+ - `pose2d.csv`
77
+ - `pose3d.csv`
78
+ - `pose_confidence.csv`
79
+ - `poseworld.csv`
80
+ - `camera.csv`
81
+ - `poseworld.trc`
82
+ - `ik.mot` and `ik.csv` when IK is run
83
+ - `external_loads.mot` and `ExternalLoads.xml` when forces are added
84
+ - `id.sto` and `id.csv` when inverse dynamics is run
85
+ - `pose_analysis.html`
86
+ - `rig_viewer.html`
87
+
88
+ ## Notebook-friendly results
89
+
90
+ Each stage returns a `StageResult` with:
91
+
92
+ - `.dataframe`
93
+ - `.artifacts`
94
+ - `.metadata`
95
+ - `.inspect()`
96
+ - `.to_csv()`
97
+ - `_repr_html_()` for a quick preview in Jupyter
98
+
99
+ ## Caveats
100
+
101
+ - OpenSim availability differs by environment; IK/ID will raise a clean error if the `opensim` Python module is unavailable.
102
+ - The FBX viewer is configurable. A default rig mapping is included and can be overridden for your asset.
103
+ - Single-camera kinetics still depend on modeling assumptions. MonoMech makes those assumptions explicit in the metadata and exported files.
104
+
105
+ See the `docs/` folder and example notebooks for end-to-end usage.
@@ -0,0 +1,17 @@
1
+ # API
2
+
3
+ ## Top-level objects
4
+
5
+ - `MonoMechPipeline`
6
+ - `PipelineConfig`
7
+ - `PoseExtractionConfig`
8
+ - `PoseWorldConfig`
9
+ - `OpenSimConfig`
10
+ - `ExternalForceSpec`
11
+ - `dumbbell_force`
12
+
13
+ ## Results
14
+
15
+ - `StageResult`
16
+ - `TrialResult`
17
+ - `BatchResult`
@@ -0,0 +1,34 @@
1
+ # Getting started
2
+
3
+ ## One file
4
+
5
+ ```python
6
+ from monomech import MonoMechPipeline, PipelineConfig
7
+
8
+ pipeline = MonoMechPipeline(PipelineConfig(output_root="outputs"))
9
+ trial = pipeline.run(
10
+ "trial.mp4",
11
+ model_path="model.osim",
12
+ )
13
+ ```
14
+
15
+ ## Multiple files
16
+
17
+ ```python
18
+ trials = pipeline.run_many(
19
+ ["walk.mp4", "squat.mp4", "curl.mp4"],
20
+ model_path="model.osim",
21
+ )
22
+ ```
23
+
24
+ ## Add a dumbbell load
25
+
26
+ ```python
27
+ from monomech import dumbbell_force
28
+
29
+ trial = pipeline.run(
30
+ "curl.mp4",
31
+ model_path="model.osim",
32
+ external_forces=[dumbbell_force(side="right", mass_kg=10.0)],
33
+ )
34
+ ```
@@ -0,0 +1,14 @@
1
+ # MonoMech
2
+
3
+ MonoMech is a single-camera biomechanics package built around modular dataframe-first stages:
4
+
5
+ 1. **pose2d**
6
+ 2. **pose3d**
7
+ 3. **poseworld**
8
+ 4. **TRC export**
9
+ 5. **inverse kinematics**
10
+ 6. **external loads**
11
+ 7. **inverse dynamics**
12
+ 8. **HTML notebook visualizations**
13
+
14
+ Every stage is inspectable and exportable.
@@ -0,0 +1,9 @@
1
+ # Notebook support
2
+
3
+ MonoMech ships with HTML-first notebook visualizers:
4
+
5
+ - `trial.poseworld.inspect()`
6
+ - `trial.pose_analysis_html()`
7
+ - `trial.rig_viewer_html()`
8
+
9
+ These return or embed HTML using Plotly and Three.js.
@@ -0,0 +1,26 @@
1
+ # Packaging
2
+
3
+ The repository includes:
4
+
5
+ - `pyproject.toml` for PyPI builds
6
+ - `conda/meta.yaml` for conda packaging
7
+ - `environment.yml` for reproducible setup
8
+ - `mkdocs.yml` for docs generation
9
+
10
+ ## Build
11
+
12
+ ```bash
13
+ python -m build
14
+ ```
15
+
16
+ ## Upload to PyPI
17
+
18
+ ```bash
19
+ twine upload dist/*
20
+ ```
21
+
22
+ ## Build a conda package
23
+
24
+ ```bash
25
+ conda build conda
26
+ ```
@@ -0,0 +1,42 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# MonoMech External Forces\n",
8
+ "A dumbbell load applied to the right hand.\n"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "metadata": {},
14
+ "execution_count": null,
15
+ "outputs": [],
16
+ "source": [
17
+ "from monomech import MonoMechPipeline, PipelineConfig, dumbbell_force\n",
18
+ "pipeline = MonoMechPipeline(PipelineConfig(output_root='outputs'))\n",
19
+ "trial = pipeline.run(\n",
20
+ " 'curl.mp4',\n",
21
+ " model_path='examples/assets/Mediapipe_Model.osim',\n",
22
+ " fbx_path='examples/assets/MovisionModel.fbx',\n",
23
+ " external_forces=[dumbbell_force(side='right', mass_kg=12.5)],\n",
24
+ ")\n",
25
+ "trial.inverse_dynamics.inspect().head()\n"
26
+ ]
27
+ }
28
+ ],
29
+ "metadata": {
30
+ "kernelspec": {
31
+ "display_name": "Python 3",
32
+ "language": "python",
33
+ "name": "python3"
34
+ },
35
+ "language_info": {
36
+ "name": "python",
37
+ "version": "3.11"
38
+ }
39
+ },
40
+ "nbformat": 4,
41
+ "nbformat_minor": 5
42
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# MonoMech Getting Started\n",
8
+ "This notebook runs the full pipeline and previews dataframe outputs.\n"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "metadata": {},
14
+ "execution_count": null,
15
+ "outputs": [],
16
+ "source": [
17
+ "from monomech import MonoMechPipeline, PipelineConfig\n",
18
+ "pipeline = MonoMechPipeline(PipelineConfig(output_root='outputs'))\n",
19
+ "trial = pipeline.run(\n",
20
+ " 'trial.mp4',\n",
21
+ " model_path='examples/assets/Mediapipe_Model.osim',\n",
22
+ " fbx_path='examples/assets/MovisionModel.fbx',\n",
23
+ ")\n",
24
+ "trial.summary()\n"
25
+ ]
26
+ },
27
+ {
28
+ "cell_type": "code",
29
+ "metadata": {},
30
+ "execution_count": null,
31
+ "outputs": [],
32
+ "source": [
33
+ "trial.pose2d.inspect().head()\n"
34
+ ]
35
+ },
36
+ {
37
+ "cell_type": "code",
38
+ "metadata": {},
39
+ "execution_count": null,
40
+ "outputs": [],
41
+ "source": [
42
+ "trial.visualizations\n"
43
+ ]
44
+ }
45
+ ],
46
+ "metadata": {
47
+ "kernelspec": {
48
+ "display_name": "Python 3",
49
+ "language": "python",
50
+ "name": "python3"
51
+ },
52
+ "language_info": {
53
+ "name": "python",
54
+ "version": "3.11"
55
+ }
56
+ },
57
+ "nbformat": 4,
58
+ "nbformat_minor": 5
59
+ }