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:

FileResponsibility
main.pyOrchestrates video → pose → marker → OpenSim export; contains the highest branching density (143 branch points over 465 lines).
app.pyFlask server that exposes a REST endpoint for job submission; makes an outbound request without a timeout.
utils.pyHub module imported by 17 other modules; high churn, deep nesting (max indentation 16).
utilsChecker.pyValidation logic; deep nesting and oversized (1345 lines).
utilsSync.py & utilsServer.pySynchronisation and server‑side helpers; both have broad except clauses.
Examples/*.pySix 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.txtPython 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:

  1. main.pyutils.py (core helpers, Ca = 17 importers, Ce = 3 imports, instability 0.7) – the hub that most code touches.
  2. utils.pyutilsChecker.py (validation, Ca = 4, Ce = 5, instability 0.56).
  3. utilsChecker.pyutilsAuth.py (authentication, Ca = 8, Ce = 1, instability 0.11).
  4. app.py makes 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 except clauses that catch Exception broadly in utils.py, utilsAuth.py, utilsAPI.py.
  • [MEDIUM/resource_safety] File opened without context manager – 5 open(...) calls in utilsAuth.py, utilsDataman.py, utilsCameraPy3.py lacking with.
  • [MEDIUM/clarity] Hub module – utils.py imported 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.py and utilsChecker.py; 5 markers in utilsServer.py.

Code‑Health Audit (9 findings, ranked by severity/confidence/production reach):

  • [HIGH] Pin third‑party GitHub Actions to a commit SHA – .github/workflows uses aws-actions/configure-aws-credentials@v1, aws-actions/amazon-ecr-login@v1.
  • [MEDIUM] Declare least‑privilege permissions for GITHUB_TOKEN – 2 workflows have no permissions block, 2 reference secrets.
  • [MEDIUM] Enable Dependabot or Renovate – 2 manifests, no update bot configured.
  • [MEDIUM] Pin the container base image by digest – docker/Dockerfile uses stanfordnmbl/opensim-python:4.3 without 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.gif is 10.5 MB.
  • [MEDIUM] Give the outbound request a timeout – app.py makes an outbound call with no timeout.
  • [MEDIUM] Add a non‑root USER to the image – docker/Dockerfile has no USER directive.
  • [LOW] Set timeout-minutes on workflow jobs – .github/workflows/ecr-dev.yml declares 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.