Everyframe · computer vision
Reading one motion.
A pose-driven pipeline that watches one golf swing, finds address, top, impact and finish from the hands, and measures the tempo golfers quote as 3 to 1. Then the analysis edits the clip: the downswing plays at quarter speed, cut at the frames the detector found.
The swing, live
One swing as the engine returns it: skeleton burned on, the phase named as it happens, the tempo revealed at impact, and the downswing stretched to quarter speed. Under it, the hands' height the detector read, with the four phases marked. The scope runs in source time; the video runs in the engine's edit, and the playhead maps between the two.
Hands height · address, top, impact, finish marked
Height is the hands' offset above the hips, divided by the torso length, so the distance to the camera cancels. Tempo is the backswing (address to top) over the downswing (top to impact). Top is the moment the hands start down in earnest; the club reverses a little after the hands peak, so this is the closer reading.
Ranked by tempo
Every swing the pipeline read, sorted by tempo. Backswing and downswing are frame counts divided by the frame rate; the ratio is the number a golfer already knows. A swing the detector could not settle (address or finish cut off, a second swing in the file) says so instead of pretending.
| Swing | View | Backswing | Downswing | Tempo | Read |
|---|
Two swings, aligned at the top
Click either clip and both play from one second before their own top, so the downswings start together. Everything after that is the difference the tempo number describes.
The pipeline
Three stages. Perception and the edit run inside the Everyframe engine; reading the phases is plain signal processing on the extracted joints, the same shape as the rep-counting showcase.
Perceive Everyframe
Person detection, then top-down pose per person, then one skeleton record per frame through
sink_pose_jsonl
. The recipe is the rep-counting one, unchanged.
// examples/ai/golf_extract_pose.rs
let dets = detect_with(&v, "dfine_l_coco", …); // person boxes
let persons = filter_detections(dets, "person");
let poses = estimate_pose_detections(&v, persons,
"rtmpose-m", …)?; // 17 COCO keypoints
sink_pose_jsonl("pose.jsonl", poses); // one line per frameRead signal processing
The hands are the mean of both wrists, relative to the hips and divided by the torso length. The swing is anchored where the hands fall fastest, which only a downswing does; the other three phases follow from that anchor. No learned model, no per-golfer rules.
# golf_phases.py fall = fall_rate(height) # how fast the hands drop impact = lowest hands inside the fastest fall address = hands leave their settled spot before it top = hands start down in earnest finish = hands held high after impact tempo = (top - address) / (impact - top)
Edit Everyframe
Back in the engine: the skeleton is drawn on the original frames, each phase name is a
drawtext
gated to its window, and
speed_ramp
plays top to impact at a quarter of the speed. Every boundary comes from the detector's output; nothing is typed by hand.
// examples/ai/golf_label.rs
v = v.try_pipe(draw_skeleton_with(poses, …))?;
for (text, a, b) in phases { // time-gated labels
v = v.pipe(drawtext(DrawText { text, enable: between(t,a,b), … }));
}
v = v.pipe(speed_ramp(&[ // the edit, from the numbers
(top, 1.0), (impact - top, 0.25), (rest, 1.0),
]));What it does not do
The page states what the pipeline measured and nothing past it. Four limits worth knowing before reading the numbers as more than they are.
No club, no ball
The pose model has 17 body joints and none for a club or a ball. Club path, face angle, ball speed and launch angle are not measured here and are not claimed.
Frame rate is the gate
Impact is known to within one frame: about 4 ms at 240 fps, 33 ms at 30 fps. A downswing lasts a quarter of a second, so at 30 fps the tempo ratio is coarse. Film fast or read the number as a range.
Consistency, not anatomy
Every number is 2D from a fixed camera and normalised by torso length. Two swings from the same spot compare cleanly; a joint angle in degrees is not on offer from one lens.
Hands, not club
Top is where the hands start down in earnest. The club reverses a little later, so the ratio here runs slightly under a club-timed one. It is stated the same way for every swing, which is what a ranking needs.