pose-platform 1.25.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.
- pose-platform-1.25.0/MANIFEST.in +50 -0
- pose-platform-1.25.0/PKG-INFO +160 -0
- pose-platform-1.25.0/README.md +137 -0
- pose-platform-1.25.0/capabilities/tools/_audio_utils.py +85 -0
- pose-platform-1.25.0/capabilities/tools/_motion_angle_profiles.py +467 -0
- pose-platform-1.25.0/capabilities/tools/_session_context.py +228 -0
- pose-platform-1.25.0/capabilities/tools/base.py +191 -0
- pose-platform-1.25.0/capabilities/tools/general/__init__.py +0 -0
- pose-platform-1.25.0/capabilities/tools/general/action_boundaries.py +220 -0
- pose-platform-1.25.0/capabilities/tools/general/energy.py +132 -0
- pose-platform-1.25.0/capabilities/tools/general/highlight.py +264 -0
- pose-platform-1.25.0/capabilities/tools/general/motion_segments.py +371 -0
- pose-platform-1.25.0/capabilities/tools/general/session_context.py +158 -0
- pose-platform-1.25.0/capabilities/tools/general/stats.py +397 -0
- pose-platform-1.25.0/capabilities/tools/general/velocity.py +291 -0
- pose-platform-1.25.0/capabilities/tools/kinematics.py +235 -0
- pose-platform-1.25.0/capabilities/tools/loader.py +693 -0
- pose-platform-1.25.0/capabilities/tools/registry.py +190 -0
- pose-platform-1.25.0/capabilities/tools/sensor_loader.py +257 -0
- pose-platform-1.25.0/capabilities/tools/sprint/__init__.py +0 -0
- pose-platform-1.25.0/capabilities/tools/sprint/_standards.py +495 -0
- pose-platform-1.25.0/capabilities/tools/sprint/motion_angles.py +836 -0
- pose-platform-1.25.0/capabilities/tools/sprint/runner_profile.py +126 -0
- pose-platform-1.25.0/capabilities/tools/sprint/running_efficiency.py +652 -0
- pose-platform-1.25.0/capabilities/tools/sprint/running_gait.py +602 -0
- pose-platform-1.25.0/capabilities/tools/sprint/running_speed.py +820 -0
- pose-platform-1.25.0/capabilities/tools/sprint/score_sprint.py +493 -0
- pose-platform-1.25.0/capabilities/utils/__init__.py +0 -0
- pose-platform-1.25.0/capabilities/utils/motion_energy.py +74 -0
- pose-platform-1.25.0/data_hub/__init__.py +5 -0
- pose-platform-1.25.0/data_hub/pipeline/__init__.py +0 -0
- pose-platform-1.25.0/data_hub/pipeline/bdy_decoder.py +80 -0
- pose-platform-1.25.0/data_hub/pipeline/ingest.py +673 -0
- pose-platform-1.25.0/data_hub/schema/__init__.py +0 -0
- pose-platform-1.25.0/data_hub/schema/dataset.py +77 -0
- pose-platform-1.25.0/data_hub/schema/motion_record.py +189 -0
- pose-platform-1.25.0/pose_platform.egg-info/PKG-INFO +160 -0
- pose-platform-1.25.0/pose_platform.egg-info/SOURCES.txt +67 -0
- pose-platform-1.25.0/pose_platform.egg-info/dependency_links.txt +1 -0
- pose-platform-1.25.0/pose_platform.egg-info/entry_points.txt +3 -0
- pose-platform-1.25.0/pose_platform.egg-info/requires.txt +15 -0
- pose-platform-1.25.0/pose_platform.egg-info/top_level.txt +4 -0
- pose-platform-1.25.0/pose_platform_core/__init__.py +16 -0
- pose-platform-1.25.0/pose_platform_core/cache_manager.py +156 -0
- pose-platform-1.25.0/pose_platform_core/gap_registry.py +195 -0
- pose-platform-1.25.0/pose_platform_core/llm_client.py +450 -0
- pose-platform-1.25.0/pose_platform_core/llm_protocol_adapter.py +202 -0
- pose-platform-1.25.0/pose_platform_core/llm_router.py +110 -0
- pose-platform-1.25.0/pose_platform_core/locale.py +46 -0
- pose-platform-1.25.0/pose_platform_core/paths.py +34 -0
- pose-platform-1.25.0/pose_platform_core/product_interface.py +102 -0
- pose-platform-1.25.0/pose_platform_core/sports_catalog.py +176 -0
- pose-platform-1.25.0/pose_platform_core/telemetry.py +53 -0
- pose-platform-1.25.0/pose_platform_core/text_sanitize.py +21 -0
- pose-platform-1.25.0/pose_platform_core/version_manager.py +214 -0
- pose-platform-1.25.0/products/__init__.py +0 -0
- pose-platform-1.25.0/products/pose_cli/__init__.py +0 -0
- pose-platform-1.25.0/products/pose_cli/annotate/__init__.py +0 -0
- pose-platform-1.25.0/products/pose_cli/annotate/server.py +289 -0
- pose-platform-1.25.0/products/pose_cli/annotate/static/index.html +258 -0
- pose-platform-1.25.0/products/pose_cli/cli.py +1709 -0
- pose-platform-1.25.0/products/pose_cli/cmd_annotate.py +176 -0
- pose-platform-1.25.0/products/pose_cli/cmd_data.py +117 -0
- pose-platform-1.25.0/products/pose_cli/cmd_serve.py +269 -0
- pose-platform-1.25.0/products/pose_cli/cmd_telemetry.py +85 -0
- pose-platform-1.25.0/products/pose_cli/locale_text.py +270 -0
- pose-platform-1.25.0/products/pose_cli/product.py +28 -0
- pose-platform-1.25.0/pyproject.toml +109 -0
- pose-platform-1.25.0/setup.cfg +4 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# ── 后端/API(完整 Pose Platform 才有)──
|
|
2
|
+
prune products/sports_assistant
|
|
3
|
+
prune products/rehab_app
|
|
4
|
+
prune api
|
|
5
|
+
|
|
6
|
+
# ── Auth / DB(仅后端需要)──
|
|
7
|
+
prune pose_platform_core/auth
|
|
8
|
+
prune pose_platform_core/db
|
|
9
|
+
exclude pose_platform_core/config.py
|
|
10
|
+
|
|
11
|
+
# ── 后端/运维模块 ──
|
|
12
|
+
exclude pose_platform_core/feedback_triage.py
|
|
13
|
+
exclude pose_platform_core/monitoring.py
|
|
14
|
+
exclude pose_platform_core/observability.py
|
|
15
|
+
exclude pose_platform_core/rate_limiter.py
|
|
16
|
+
exclude pose_platform_core/capability_negotiator.py
|
|
17
|
+
exclude pose_platform_core/wtp_analysis.py
|
|
18
|
+
|
|
19
|
+
# ── CLI 后端/内部命令 ──
|
|
20
|
+
exclude products/pose_cli/admin_client.py
|
|
21
|
+
exclude products/pose_cli/cmd_annotations.py
|
|
22
|
+
exclude products/pose_cli/cmd_calib.py
|
|
23
|
+
exclude products/pose_cli/cmd_data_seed.py
|
|
24
|
+
exclude products/pose_cli/cmd_deploy.py
|
|
25
|
+
exclude products/pose_cli/cmd_ops.py
|
|
26
|
+
exclude products/pose_cli/cmd_rxlib.py
|
|
27
|
+
exclude products/pose_cli/cmd_wtp.py
|
|
28
|
+
|
|
29
|
+
# ── 平台层运动(不包含在 CLI 公开包中)──
|
|
30
|
+
prune capabilities/tools/badminton
|
|
31
|
+
prune capabilities/tools/_internal
|
|
32
|
+
prune capabilities/recognition
|
|
33
|
+
exclude capabilities/mcp_server.py
|
|
34
|
+
|
|
35
|
+
# ── data_hub DB/标注模块 ──
|
|
36
|
+
prune data_hub/registry
|
|
37
|
+
prune data_hub/annotation
|
|
38
|
+
prune data_hub/annotations
|
|
39
|
+
prune data_hub/catalog
|
|
40
|
+
exclude data_hub/pipeline/purge.py
|
|
41
|
+
exclude data_hub/pipeline/template_slicer.py
|
|
42
|
+
|
|
43
|
+
# ── Web 标注工具静态文件 ──
|
|
44
|
+
include products/pose_cli/annotate/static/index.html
|
|
45
|
+
|
|
46
|
+
# ── 开发文件 ──
|
|
47
|
+
prune tests
|
|
48
|
+
prune docs
|
|
49
|
+
prune .pytest_cache
|
|
50
|
+
prune .pose
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pose-platform
|
|
3
|
+
Version: 1.25.0
|
|
4
|
+
Summary: Pose CLI — open motion-analysis toolkit for sports scientists
|
|
5
|
+
License: Pose Platform License v1.0
|
|
6
|
+
Project-URL: Homepage, https://posecap.com/posecli/
|
|
7
|
+
Project-URL: Documentation, https://posecap.com/posecli/docs/
|
|
8
|
+
Project-URL: Repository, https://github.com/posecap/pose-platform
|
|
9
|
+
Keywords: motion-analysis,sports-science,biomechanics,skeleton-tracking,pose-estimation
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Provides-Extra: llm
|
|
22
|
+
Provides-Extra: server
|
|
23
|
+
|
|
24
|
+
# Pose CLI
|
|
25
|
+
|
|
26
|
+
**Open motion-analysis toolkit for sports scientists.**
|
|
27
|
+
`pip install pose-platform` — analyze 3D skeleton data on your machine.
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/pose-platform/)
|
|
30
|
+
[](https://www.python.org/)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install pose-platform
|
|
34
|
+
pose analyze data/session.csv --tool stats
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## What is Pose CLI?
|
|
40
|
+
|
|
41
|
+
Pose CLI turns 3D body-skeleton data into reproducible sports analytics.
|
|
42
|
+
It runs **entirely on your machine** — your data never leaves your computer.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Pose Coach Recording → JointData3D CSV → pose analyze --tool <name> → JSON Output
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**11 built-in analysis tools**, two supported sports:
|
|
49
|
+
|
|
50
|
+
| Category | Tools | Sport |
|
|
51
|
+
|----------|-------|-------|
|
|
52
|
+
| **General** (any movement) | `stats`, `detect_peak_energy`, `segment_motion_phases`, `detect_velocity`, `detect_action_boundaries`, `detect_highlight` | `freeplay` |
|
|
53
|
+
| **Running** (reference implementation) | `measure_running_speed`, `score_sprint`, `analyze_running_gait`, `score_running_efficiency` | `sprint` |
|
|
54
|
+
| **Multi-sport** | `analyze_motion_angles` | both |
|
|
55
|
+
|
|
56
|
+
Sprint tools serve as a reference for building your own sport-specific tools.
|
|
57
|
+
[See contributing guide →](https://posecap.com/posecli/docs/#contributing)
|
|
58
|
+
|
|
59
|
+
## Quickstart
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install pose-platform
|
|
63
|
+
|
|
64
|
+
# Download sample data
|
|
65
|
+
curl -O https://posecap.com/samples/sample_sprint.csv
|
|
66
|
+
|
|
67
|
+
# Run your first analysis
|
|
68
|
+
pose analyze sample_sprint.csv --tool stats
|
|
69
|
+
|
|
70
|
+
# Explore available tools
|
|
71
|
+
pose tools && pose sports
|
|
72
|
+
|
|
73
|
+
# LLM-powered analysis (optional)
|
|
74
|
+
export POSE_DEEPSEEK_API_KEY=sk-xxx
|
|
75
|
+
pose chat ./data
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
- **Python 3.10+** required. Works on macOS, Linux, Windows.
|
|
81
|
+
- **Optional**: `pip install openai anthropic` for LLM chat support.
|
|
82
|
+
- **Full guide**: [posecap.com/posecli/docs/](https://posecap.com/posecli/docs/)
|
|
83
|
+
|
|
84
|
+
## Data Format
|
|
85
|
+
|
|
86
|
+
Pose CLI reads **JointData3D CSV** (12-column, no header):
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
timestamp, joint, wx, wy, wz, mx, my, mz, ldq_x, ldq_y, ldq_z, ldq_w
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Record with Pose Coach (iOS, TestFlight) or convert from OpenPose / MediaPipe / motion capture.
|
|
93
|
+
[Data format reference →](https://posecap.com/posecli/docs/#data-format)
|
|
94
|
+
|
|
95
|
+
## Commands
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pose analyze <file.csv> --tool <name> [--param key=value] # Run analysis
|
|
99
|
+
pose tools [--sport <id>] [--detail] # List tools
|
|
100
|
+
pose sports # List sports
|
|
101
|
+
pose gaps list|submit|show|summary # Track feature requests
|
|
102
|
+
pose chat [data_dir] # LLM-powered analysis
|
|
103
|
+
pose cache list|clear # Manage cache
|
|
104
|
+
pose telemetry stats [--since 7d] # Usage statistics
|
|
105
|
+
pose version [--changelog] # Version info
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Extending Pose CLI
|
|
109
|
+
|
|
110
|
+
Every analysis tool is a Python class. Build your own:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from capabilities.tools.base import DirectTool
|
|
114
|
+
from capabilities.tools.loader import load_pose
|
|
115
|
+
import json
|
|
116
|
+
from pathlib import Path
|
|
117
|
+
|
|
118
|
+
class MyTool(DirectTool):
|
|
119
|
+
name = "my_tool"
|
|
120
|
+
supported_sports = ["basketball"] # or [] for all
|
|
121
|
+
input_schema = {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}
|
|
122
|
+
|
|
123
|
+
def run(self, tool_input: dict, output_dir: Path) -> str:
|
|
124
|
+
pose = load_pose(tool_input["path"])
|
|
125
|
+
# your analysis here
|
|
126
|
+
return json.dumps({"result": 42}, ensure_ascii=False)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Register a new sport in 3 lines of config.
|
|
130
|
+
[Contributing →](https://posecap.com/posecli/docs/#contributing)
|
|
131
|
+
|
|
132
|
+
## From Source (Platform Developers)
|
|
133
|
+
|
|
134
|
+
Pose CLI is the public distribution of the Pose Platform. The full platform
|
|
135
|
+
(in this repository) also includes the Pose Coach backend, operations tooling,
|
|
136
|
+
and badminton-specific analysis tools — these are excluded from the pip package.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone <repo-url>
|
|
140
|
+
cd pose_platform
|
|
141
|
+
pip install -e .
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
Pose CLI is distributed under the [Pose Platform License v1.0](LICENSE.txt):
|
|
147
|
+
- **Research use**: free for academic and educational purposes
|
|
148
|
+
- **Commercial use**: requires a separate agreement
|
|
149
|
+
- **Attribution**: cite the Pose Platform in publications
|
|
150
|
+
|
|
151
|
+
## Citation
|
|
152
|
+
|
|
153
|
+
```bibtex
|
|
154
|
+
@software{pose_platform,
|
|
155
|
+
title = {Pose Platform: Open Motion Analysis Toolkit},
|
|
156
|
+
author = {{PoseCap Inc.}},
|
|
157
|
+
year = {2026},
|
|
158
|
+
url = {https://github.com/posecap/pose-platform},
|
|
159
|
+
}
|
|
160
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Pose CLI
|
|
2
|
+
|
|
3
|
+
**Open motion-analysis toolkit for sports scientists.**
|
|
4
|
+
`pip install pose-platform` — analyze 3D skeleton data on your machine.
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/pose-platform/)
|
|
7
|
+
[](https://www.python.org/)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install pose-platform
|
|
11
|
+
pose analyze data/session.csv --tool stats
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## What is Pose CLI?
|
|
17
|
+
|
|
18
|
+
Pose CLI turns 3D body-skeleton data into reproducible sports analytics.
|
|
19
|
+
It runs **entirely on your machine** — your data never leaves your computer.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Pose Coach Recording → JointData3D CSV → pose analyze --tool <name> → JSON Output
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**11 built-in analysis tools**, two supported sports:
|
|
26
|
+
|
|
27
|
+
| Category | Tools | Sport |
|
|
28
|
+
|----------|-------|-------|
|
|
29
|
+
| **General** (any movement) | `stats`, `detect_peak_energy`, `segment_motion_phases`, `detect_velocity`, `detect_action_boundaries`, `detect_highlight` | `freeplay` |
|
|
30
|
+
| **Running** (reference implementation) | `measure_running_speed`, `score_sprint`, `analyze_running_gait`, `score_running_efficiency` | `sprint` |
|
|
31
|
+
| **Multi-sport** | `analyze_motion_angles` | both |
|
|
32
|
+
|
|
33
|
+
Sprint tools serve as a reference for building your own sport-specific tools.
|
|
34
|
+
[See contributing guide →](https://posecap.com/posecli/docs/#contributing)
|
|
35
|
+
|
|
36
|
+
## Quickstart
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install pose-platform
|
|
40
|
+
|
|
41
|
+
# Download sample data
|
|
42
|
+
curl -O https://posecap.com/samples/sample_sprint.csv
|
|
43
|
+
|
|
44
|
+
# Run your first analysis
|
|
45
|
+
pose analyze sample_sprint.csv --tool stats
|
|
46
|
+
|
|
47
|
+
# Explore available tools
|
|
48
|
+
pose tools && pose sports
|
|
49
|
+
|
|
50
|
+
# LLM-powered analysis (optional)
|
|
51
|
+
export POSE_DEEPSEEK_API_KEY=sk-xxx
|
|
52
|
+
pose chat ./data
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
- **Python 3.10+** required. Works on macOS, Linux, Windows.
|
|
58
|
+
- **Optional**: `pip install openai anthropic` for LLM chat support.
|
|
59
|
+
- **Full guide**: [posecap.com/posecli/docs/](https://posecap.com/posecli/docs/)
|
|
60
|
+
|
|
61
|
+
## Data Format
|
|
62
|
+
|
|
63
|
+
Pose CLI reads **JointData3D CSV** (12-column, no header):
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
timestamp, joint, wx, wy, wz, mx, my, mz, ldq_x, ldq_y, ldq_z, ldq_w
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Record with Pose Coach (iOS, TestFlight) or convert from OpenPose / MediaPipe / motion capture.
|
|
70
|
+
[Data format reference →](https://posecap.com/posecli/docs/#data-format)
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pose analyze <file.csv> --tool <name> [--param key=value] # Run analysis
|
|
76
|
+
pose tools [--sport <id>] [--detail] # List tools
|
|
77
|
+
pose sports # List sports
|
|
78
|
+
pose gaps list|submit|show|summary # Track feature requests
|
|
79
|
+
pose chat [data_dir] # LLM-powered analysis
|
|
80
|
+
pose cache list|clear # Manage cache
|
|
81
|
+
pose telemetry stats [--since 7d] # Usage statistics
|
|
82
|
+
pose version [--changelog] # Version info
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Extending Pose CLI
|
|
86
|
+
|
|
87
|
+
Every analysis tool is a Python class. Build your own:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from capabilities.tools.base import DirectTool
|
|
91
|
+
from capabilities.tools.loader import load_pose
|
|
92
|
+
import json
|
|
93
|
+
from pathlib import Path
|
|
94
|
+
|
|
95
|
+
class MyTool(DirectTool):
|
|
96
|
+
name = "my_tool"
|
|
97
|
+
supported_sports = ["basketball"] # or [] for all
|
|
98
|
+
input_schema = {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}
|
|
99
|
+
|
|
100
|
+
def run(self, tool_input: dict, output_dir: Path) -> str:
|
|
101
|
+
pose = load_pose(tool_input["path"])
|
|
102
|
+
# your analysis here
|
|
103
|
+
return json.dumps({"result": 42}, ensure_ascii=False)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Register a new sport in 3 lines of config.
|
|
107
|
+
[Contributing →](https://posecap.com/posecli/docs/#contributing)
|
|
108
|
+
|
|
109
|
+
## From Source (Platform Developers)
|
|
110
|
+
|
|
111
|
+
Pose CLI is the public distribution of the Pose Platform. The full platform
|
|
112
|
+
(in this repository) also includes the Pose Coach backend, operations tooling,
|
|
113
|
+
and badminton-specific analysis tools — these are excluded from the pip package.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
git clone <repo-url>
|
|
117
|
+
cd pose_platform
|
|
118
|
+
pip install -e .
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
Pose CLI is distributed under the [Pose Platform License v1.0](LICENSE.txt):
|
|
124
|
+
- **Research use**: free for academic and educational purposes
|
|
125
|
+
- **Commercial use**: requires a separate agreement
|
|
126
|
+
- **Attribution**: cite the Pose Platform in publications
|
|
127
|
+
|
|
128
|
+
## Citation
|
|
129
|
+
|
|
130
|
+
```bibtex
|
|
131
|
+
@software{pose_platform,
|
|
132
|
+
title = {Pose Platform: Open Motion Analysis Toolkit},
|
|
133
|
+
author = {{PoseCap Inc.}},
|
|
134
|
+
year = {2026},
|
|
135
|
+
url = {https://github.com/posecap/pose-platform},
|
|
136
|
+
}
|
|
137
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Audio sidecar utilities for loading and matching iOS hit-sound events.
|
|
3
|
+
|
|
4
|
+
Sidecar format (schemaVersion=1):
|
|
5
|
+
{
|
|
6
|
+
"schemaVersion": 1,
|
|
7
|
+
"segmentStartSeconds": float,
|
|
8
|
+
"segmentEndSeconds": float,
|
|
9
|
+
"detectorThresholdRatio": 2.5,
|
|
10
|
+
"events": [{"timestampSeconds": float, "ratio": float}, ...]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Naming convention (confirmed from AudioEventsSidecar.swift):
|
|
14
|
+
<sessionStem>_audio_events.json
|
|
15
|
+
where sessionStem = csv stem with "_3d" / "_2d" suffix stripped.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
_AUDIO_SIDECAR_SUFFIX = "_audio_events.json"
|
|
24
|
+
|
|
25
|
+
# ARSession audio buffer introduces a fixed ~21 ms delay relative to body3D timestamps.
|
|
26
|
+
_AUDIO_SYSTEMATIC_DELAY_S = 0.021
|
|
27
|
+
|
|
28
|
+
# Tolerance for matching an audio event to a detected swing peak.
|
|
29
|
+
# Accounts for: delay compensation residual + frame quantisation (~1/fps at 60 Hz ≈ 17 ms).
|
|
30
|
+
AUDIO_PEAK_TOL_S = 0.06
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _sidecar_path(csv_path: Path) -> Path:
|
|
34
|
+
"""Return the expected audio sidecar path for a given body-3D CSV."""
|
|
35
|
+
stem = csv_path.stem
|
|
36
|
+
for sfx in ("_3d", "_2d"):
|
|
37
|
+
if stem.endswith(sfx):
|
|
38
|
+
stem = stem[: -len(sfx)]
|
|
39
|
+
break
|
|
40
|
+
return csv_path.parent / (stem + _AUDIO_SIDECAR_SUFFIX)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def load_audio_events(csv_path: Path) -> list[dict]:
|
|
44
|
+
"""
|
|
45
|
+
Load audio hit-sound events from the companion sidecar file.
|
|
46
|
+
|
|
47
|
+
Returns an empty list when the sidecar does not exist (silent degradation).
|
|
48
|
+
Applies systematic delay compensation and filters events below the detector
|
|
49
|
+
threshold used at recording time.
|
|
50
|
+
|
|
51
|
+
Return format: [{"time_s": float, "ratio": float}, ...] sorted by time_s.
|
|
52
|
+
"""
|
|
53
|
+
sidecar = _sidecar_path(csv_path)
|
|
54
|
+
if not sidecar.exists():
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
raw = json.loads(sidecar.read_text(encoding="utf-8"))
|
|
58
|
+
threshold = raw.get("detectorThresholdRatio", 2.5)
|
|
59
|
+
events = [
|
|
60
|
+
{
|
|
61
|
+
"time_s": e["timestampSeconds"] - _AUDIO_SYSTEMATIC_DELAY_S,
|
|
62
|
+
"ratio": e["ratio"],
|
|
63
|
+
}
|
|
64
|
+
for e in raw.get("events", [])
|
|
65
|
+
if e["ratio"] >= threshold
|
|
66
|
+
]
|
|
67
|
+
return sorted(events, key=lambda x: x["time_s"])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def audio_corroborates(
|
|
71
|
+
peak_s: float,
|
|
72
|
+
audio_events: list[dict],
|
|
73
|
+
tol_s: float = AUDIO_PEAK_TOL_S,
|
|
74
|
+
) -> tuple[bool, float | None]:
|
|
75
|
+
"""
|
|
76
|
+
Check whether any audio event falls within *tol_s* of *peak_s*.
|
|
77
|
+
|
|
78
|
+
Returns (matched, best_ratio) where best_ratio is the highest ratio among
|
|
79
|
+
matching events, or None when no event matches.
|
|
80
|
+
"""
|
|
81
|
+
matches = [e for e in audio_events if abs(e["time_s"] - peak_s) < tol_s]
|
|
82
|
+
if not matches:
|
|
83
|
+
return False, None
|
|
84
|
+
best = max(matches, key=lambda x: x["ratio"])
|
|
85
|
+
return True, best["ratio"]
|