The Problem
OpenCap‑core processes multi‑video inputs to produce 3‑D marker positions and OpenSim‑compatible kinematics, but the pipeline contains several structural weaknesses that make it fragile for production use: deep nesting, oversized modules, broad exception handling, and duplicated logic across example scripts. These issues increase cognitive load for developers and raise the risk of runtime failures or security‑relevant gaps.
What This Does
OpenCap‑core is a data‑processing pipeline that takes two or more synchronized videos, runs pose estimation (TensorFlow / OpenPose) and marker‑augmentation, and writes OpenSim‑format outputs. Core logic lives in main.py (entry point for the CLI pipeline) and app.py (Flask web service). Pose estimation and marker handling are delegated to the MarkerAugmenter/ and mmpose/ sub‑packages; camera intrinsics pickle files stored under CameraIntrinsics/ provide per‑device calibration data. The pipeline writes results to a local directory and, when run via the web app, pushes them to a cloud database.
Key files and their responsibilities:
| File | Responsibility |
|---|---|
main.py | Orchestrates video → pose → marker → OpenSim export; contains the highest branching density (143 branch points over 465 lines). |
app.py | Flask server that exposes a REST endpoint for job submission; makes an outbound request without a timeout. |
utils.py | Hub module imported by 17 other modules; high churn, deep nesting (max indentation 16). |
utilsChecker.py | Validation logic; deep nesting and oversized (1345 lines). |
utilsSync.py & utilsServer.py | Synchronisation and server‑side helpers; both have broad except clauses. |
Examples/*.py | Six example scripts that repeat ~89 six‑line blocks for data download, metadata changes, and public‑session creation. |
docker/ | Build definitions for OpenPose, mmpose, and the full OpenCap image. |
requirements.txt & openpose/requirements.txt | Python dependencies; no lockfile, so builds are non‑reproducible. |
How It Is Wired
The internal call graph contains 40 Python modules and 56 import edges with no circular dependencies. Execution starts at either main.py (CLI) or app.py (web). From main.py the flow proceeds:
main.py→utils.py(core helpers, Ca = 17 importers, Ce = 3 imports, instability 0.7) – the hub that most code touches.utils.py→utilsChecker.py(validation, Ca = 4, Ce = 5, instability 0.56).utilsChecker.py→utilsAuth.py(authentication, Ca = 8, Ce = 1, instability 0.11).app.pymakes a single outbound HTTP call (no timeout) to a cloud‑processing endpoint.
The most connected modules and their instability scores (higher = more ripple risk) are:
utils(Ca 17, Ce 3, instability 0.15) – many depend on it, but it imports little.main(Ca 3, Ce 7, instability 0.7) – few importers, but it imports widely; a change here ripples through the pipeline.utilsAPI(Ca 7, Ce 0, instability 0) – safe, no outward imports.
Because utils.py is a hub, modifications there affect 17 downstream modules; any bug or API shift has a broad blast radius.
How To Use It
Setup (grounded in repo files):
# 1. Clone the repo (use the exact URL)
git clone https://github.com/moses-y/opencap-core.git
# 2. Create a conda environment (as described in README)
conda create -n opencap python=3.9 pip
conda activate opencap
# 3. Install OpenSim (Conda channel)
conda install -c opensim-org opensim=4.4=py39np120
# 4. Install Python dependencies (requirements.txt exists)
pip install -r requirements.txt # note: no lockfile – consider pip‑lock or Dependabot later
# 5. (Optional) Build the Docker image for a reproducible environment
docker build -t opencap-core -f docker/Dockerfile .
Configuration – the Flask app reads environment variables from .env (not committed; create one) and camera intrinsics pickles from CameraIntrinsics/<device>/Deployed/cameraIntrinsics.pickle. No secret keys are committed; add any required API keys to your environment.
Running it – two entry points:
- CLI pipeline (process videos locally): ``
bash python main.py --input videos/ --output results/`` - Web service (run the API): ``
bash python app.py # starts Flask on http://0.0.0.0:5000``
Both entry points accept --help for available flags.
Real‑World Use
A researcher records two iPhone videos of a subject walking, places them in videos/, and runs:
python main.py --input videos/ --output kinematics/
The script extracts pose estimates (using TensorFlow + OpenPose), triangulates 3‑D marker positions with the intrinsics from CameraIntrinsics/iPhone13,3/Deployed/cameraIntrinsics.pickle, and writes *.mot and *.xml files compatible with OpenSim. The resulting kinematics can be fed into opencap-processing to compute joint kinetics (forces). If the researcher needs a quick web view, they start app.py and upload the same videos through the local UI; the server stores the output in a cloud bucket visible at app.opencap.ai.
Code Health & Issues
Measured static‑analysis findings (60 total, 24 high, 33 medium, 3 low, 9 distinct kinds):
- [HIGH/cognitive_load] Deep nesting – 27 occurrences in
utils.py,utilsChecker.py,main.py; max indentation depth 16. - [HIGH/cognitive_load] Oversized files – 7 files exceed 1000 lines (
utils.py,utilsSync.py,utilsChecker.py; 1345 lines each). - [MEDIUM/resilience] Broad exception handling – 12
exceptclauses that catchExceptionbroadly inutils.py,utilsAuth.py,utilsAPI.py. - [MEDIUM/resource_safety] File opened without context manager – 5
open(...)calls inutilsAuth.py,utilsDataman.py,utilsCameraPy3.pylackingwith. - [MEDIUM/clarity] Hub module –
utils.pyimported by 17 modules; churn high‑blast‑radius. - [HIGH/clarity] Duplicated code blocks – 89 repeated 6‑line fragments across 20 example files (
Examples/batchDownloadData.py,Examples/changeSessionMetadata.py, …). - [MEDIUM/cognitive_load] High branching density – 143 branch points over 465 lines in
main.py,Examples/checkDataForSubject.py,Examples/reprocessSessions.py. - [LOW/clarity] 3 TODO/FIXME markers in
tests/test_main.pyandutilsChecker.py; 5 markers inutilsServer.py.
Code‑Health Audit (9 findings, ranked by severity/confidence/production reach):
- [HIGH] Pin third‑party GitHub Actions to a commit SHA –
.github/workflowsusesaws-actions/configure-aws-credentials@v1,aws-actions/amazon-ecr-login@v1. - [MEDIUM] Declare least‑privilege permissions for
GITHUB_TOKEN– 2 workflows have nopermissionsblock, 2 reference secrets. - [MEDIUM] Enable Dependabot or Renovate – 2 manifests, no update bot configured.
- [MEDIUM] Pin the container base image by digest –
docker/Dockerfileusesstanfordnmbl/opensim-python:4.3without a digest. - [MEDIUM] Gate pull requests on a dependency vulnerability scan – no dependency scan in CI.
- [MEDIUM] Move large binaries to Git LFS or out of the repo –
media/cut_fastAndSlow.gifis 10.5 MB. - [MEDIUM] Give the outbound request a timeout –
app.pymakes an outbound call with no timeout. - [MEDIUM] Add a non‑root USER to the image –
docker/Dockerfilehas noUSERdirective. - [LOW] Set
timeout-minuteson workflow jobs –.github/workflows/ecr-dev.ymldeclares no job timeout.
The Bottom Line
OpenCap‑core delivers a functional end‑to‑end pipeline for turning smartphone videos into OpenSim kinematics, but its codebase suffers from deep nesting, oversized modules, duplicated logic, and missing reproducibility guards (no lockfile, mutable Docker base, unpinned Actions). The hub utils.py and the entry points main.py/app.py are the critical touch points; changes there ripple widely. Teams that can tolerate the current operational overhead and are willing to invest in refactoring the high‑risk modules will find the pipeline useful; others should consider the hosted app.opencap.ai service instead.