Everyframe · computer vision
One swing over another.
The engine cuts a reference golfer out of their clip. The pass scales the cutouts to the student's build, puts the hips together at address, and warps time so address, top, impact and finish meet. The ghost then plays over the student's swing. An overlay to look at. Nothing is measured.
The overlay
Left, the student's swing with the ghost over it; the readout names the phase and both clocks, since the ghost runs at its own pace between phases. Right, the three moments that matter, side by side, the hands' paths drawn: the student in amber, the ghost in blue.
The pair
Student in amber, ghost in blue, both hands' paths
The ghost is the reference golfer's cutout from the strobe read, keyed back out of the engine's render. It is tinted and desaturated so it never passes for the student, and the hips anchor keeps it on the student's body from address to finish; the reference's own sway is taken out, which is the price of an overlay that stays put.
Lining two swings up
Three moves, all from the pose the tempo read already had. Scale: the ghost's torso is stretched to the student's, shoulder centre to hip centre. Place: the hips meet at address, and with the hips anchor they keep meeting every frame. Time: the ghost plays at whatever pace makes its four phases land on the student's.
| Segment | Student | Ghost | Ghost pace |
|---|
Mirroring is decided from the pose: which side of the hips the hands hang at address. A pace above 1 means the ghost's segment is longer than the student's and plays faster to fit.
Pipeline
The strobe read's cutout pass on the reference, then one numpy pass that aligns and renders.
Cut the reference out golf_cutout.rs
The same pass the strobe read uses:
segment
with SAM2 and one centred prompt on a square around a body anchor,
mask_composite
painting the rest magenta, three anchors so every frame of the swing has a plausible mask.
Align golf_ghost.py
Scale by torso length, mirror if the two face opposite ways, put the hip centres together at address. With the hips anchor, an extra shift per frame keeps them together through the swing.
scale = torso(student) / torso(reference) mirror = facing(student) != facing(reference) offset = hip(student, address) - scale * hip(reference, address) shift[i] = hip(student, i) - place(hip(reference, warp(i))) # the hips anchor
Warp time and render golf_ghost.py
For every student frame, its time maps to the reference's between matching phases, the nearest reference frame is keyed out, tinted, scaled, shifted and pasted at 55% over the student. A clip, a poster and the triptych.
t_ref = interp(t, [address, top, impact, finish](student), [...](reference)) tile = tint(scale(cutout[nearest(t_ref)])) frame = paste(student[i], tile, alpha * 0.55, origin + shift[i])
What it does not do
An overlay is not a comparison. These are the honest edges.
The reference and the student were not filmed for each other. A wedge and a driver put the hands in different places at address, and the ghost shows that gap as if it were technique.
Torso length sets the scale, so the ghost's legs land wherever the reference's leg-to-torso ratio puts them. Feet a little off is the reference's build, not the student's stance.
With the hips anchor the ghost follows the student's hips every frame, so the reference's own weight shift is removed. The address anchor keeps it, and the ghost then drifts a torso length by impact.
No angles, no distances, no verdict. The tempo and stroke reads measure; this one shows two swings on one frame and stops there.