Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Golf Swing Analyzer (v1)

Analyzes a golf swing video using pose estimation (MediaPipe) and overlays:

  • Dots on body landmarks (shoulders, elbows, wrists, hips, knees, ankles)
  • Lines connecting them into a skeleton
  • Angle triangles (e.g. spine tilt vs. vertical), color-coded green/orange/red depending on how close to instructional target ranges
  • Wrist trail showing the swing arc/path over recent frames (smoothed — the tracked point is EMA-damped and the drawn line is moving-averaged, so the tracer reads as a clean curve rather than jaggy/shaky segments; tune with TRACER_EMA and TRACER_SMOOTH_WINDOW in src/swing_analyzer/analyze.py)
  • Swing plane line (down-the-line view) extrapolated through shoulders/hands

It also does lightweight swing-phase detection (address / top of backswing / impact / finish) and outputs a metrics report.

Setup

Requires Python 3.9–3.12. This tool pins mediapipe==0.10.14 (see below), which has no wheels for Python 3.13+ — pip install will fail with an error like Package 'swing-analyzer' requires a different Python if your default python/pip is 3.13 or newer (e.g. a fresh Windows install with only the latest Python). Install a 3.9–3.12 build and use that specifically, ideally in a virtual environment:

# macOS/Linux
python3.12 -m venv .venv
source .venv/bin/activate

# Windows (py launcher picks a specific version even if a newer one is default)
py -3.12 -m venv .venv
.venv\Scripts\activate

Then, from inside the project folder, with the venv active:

pip install -e .

This installs a swing command with three subcommands: analyze, compare, full. Run swing --help, or swing <subcommand> --help, for the full flag list at any time.

Note: pin mediapipe==0.10.14 — newer 0.10.3x releases dropped the legacy mediapipe.solutions API in favor of a Tasks API that requires a separately downloaded model file. 0.10.14 keeps the simple bundled-model API this tool uses.

Outputs always land in ./output/ relative to wherever you run swing, not the install location — so cd to your videos first.

Usage

Single view:

swing analyze --face-on my_swing.mp4

Down-the-line view:

swing analyze --dtl my_swing_dtl.mp4

Both angles at once (produces a synced side-by-side video too):

swing analyze --face-on face.mp4 --dtl dtl.mp4

Compare mode

Diff two swings against each other — e.g. same swing with different club/shaft builds, or before/after a change:

swing compare --a old_shaft.mp4 --b new_shaft.mp4 \
    --label-a "Stock shaft" --label-b "Ventus Blue 7X"

Add --view dtl if both clips are down-the-line rather than face-on.

Outputs in ./output/: annotated_<a>.mp4, annotated_<b>.mp4, compare_side_by_side.mp4, and compare_report.md (metrics table + per-swing assessment).

Face blur (anonymize)

Pass --blur-face to pixelate the golfer's face in the output (uses the tracked face landmarks, so the mosaic follows the head through the swing):

# compare mode — blurs the first swing (--a) only; the reference is left as-is
swing compare --a my_swing.mp4 --b reference.mp4 --blur-face
swing compare --a my_swing.mp4 --b other.mp4 --blur-face --blur-face-b  # blur both

# standalone
swing analyze --face-on my_swing.mp4 --blur-face

In compare mode --blur-face anonymizes only your clip (--a); add --blur-face-b if you also want the reference blurred.

The blur box is temporally smoothed — EMA-averaged frame to frame to reduce jitter, and held through short tracking gaps (up to FACE_BLUR_HOLD_FRAMES, ~0.4s) so it doesn't flicker off on a blurry frame where pose tracking briefly drops. Both FACE_BLUR_SMOOTHING and FACE_BLUR_HOLD_FRAMES are constants in src/swing_analyzer/analyze.py.

Auto-zoom (framing match)

Clips shot from different distances make one golfer look much smaller than the other. Before syncing, each clip's body size is measured (the nose→ankles box as a fraction of frame height, median over the swing) and the clip is zoomed in and panned down to a standard framing:

  • Standard zoom box — the golfer's body is zoomed to fill ~50% of the frame height (STANDARD_BODY_FRACTION). In compare mode the tighter of the two clips raises this so both clips stay matched to each other (e.g. your range clip zooms in to match a tour-pro reference).
  • Standard ground line — the clip is panned down so the feet (and the ball, which sits at the feet) land ~85% down the frame (STANDARD_FEET_Y), so every clip shares the same ground line and the ball/feet are always in view.

This runs in both compare and standalone (swing analyze) modes. It only ever zooms in (never adds borders) and crops at the original aspect ratio, so the body is never stretched. The two standards are constants at the top of src/swing_analyzer/analyze.py — override them there (or pass target_fraction to match_framing()); there is deliberately no command-line flag.

Slow-motion & tempo sync

Every clip is checked on load: swing tempo is measured from the downswing (top-of-backswing → impact, the fastest and most consistent part of a swing). A real-time downswing is ~0.2–0.35s; anything that plays back faster than ~0.8s is treated as real-time and slowed down so the downswing spans ~1.5s, while a clip that's already slow-mo is left as-is. In compare mode both clips are slowed to that same tempo so they play at matched speed.

The compare_side_by_side.mp4 then does a piecewise time-warp — backswing, downswing, and follow-through are each resampled to a shared length — so top-of-backswing and impact line up across the two clips, not just the first frame.

Guardrails keep pathological clips sane: slowdown is capped at 8×, a retimed clip never plays longer than 20s, and the side-by-side trims excess backswing/follow-through context. Tunables live at the top of src/swing_analyzer/analyze.py (SLOWMO_*). This all leans on the heuristic phase detector, so it works best on a clean, tightly-trimmed single-swing clip — feed it a 20s highlight reel and top/impact detection (and therefore the tempo/sync) gets unreliable.

Output

All in ./output/:

  • annotated_<name>.mp4 — video with overlays
  • side_by_side.mp4 — if both views were provided
  • report.md — phase frame numbers, key metrics, and flagged issues

Tips for good input video

  • Frame the whole swing (address to finish) in view, camera roughly waist-to-head height
  • Face-on: camera directly facing you, perpendicular to target line
  • Down-the-line: camera behind you, aligned with the target line
  • Plain background helps pose detection; avoid other people/objects in frame
  • 30fps+ is fine; higher fps (60/120) gives smoother phase detection around impact

Known limitations (v1)

  • 2D single-camera pose estimation — no true 3D depth, so some angles (especially swing plane in face-on view) are approximate.
  • Phase detection is a simple heuristic based on wrist height/velocity, not a robust event detector — works best with a clear address position held briefly and a normal tempo swing.
  • No clubhead or clubshaft tracking (MediaPipe tracks body only) — swing plane line is a proxy through hands, not the actual shaft.
  • No ball flight / clubhead speed data — that needs radar/launch-monitor input.
  • Target ranges in TARGETS (in src/swing_analyzer/analyze.py) are rough instructional benchmarks, not personalized — worth tuning to your own baseline over time rather than treating as absolute truth.

Extending

  • Compare mode (src/swing_analyzer/compare.py) is scaffolded — it's a thin wrapper that calls analyze_video() on both clips and diffs the summary dicts. Natural next steps: frame-aligned overlay (warp swing B's timeline onto A's phase markers so both hit "top of backswing" at the same frame), a ghost/overlay video (draw both skeletons on one frame, semi-transparent), or exporting the comparison table as CSV for tracking across many sessions.
  • To track club-specific data (shaft lean, clubface angle) you'd need either a marker on the club visible to a second detector, or a dedicated launch monitor/radar unit — video-only pose estimation can't see the club reliably.

About

Golf Swing Analyzer. Analyze your swing video against another, or get both Face on and DTL swings analyzed together.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages