BowPose
A keypoint model that finds an archery bow in a video frame: the riser, limb tips and stabilizers, for Olympic recurve, barebow and compound bows. It's built for ShotLab, a multi-camera archery form-analysis app, to run next to a human pose model so a shot can be analysed by both the archer's body and the bow.
Status: first release,
r18_v1(November 2026). Trained on 100,000 synthetic renders. On synthetic validation images it puts 85% of keypoints within 5 px and 93% within 10 px; accuracy on real video hasn't been measured yet. See Accuracy.
Keypoints
| # | Name | Notes |
|---|---|---|
| 0 | riser_top |
Upper limb pocket |
| 1 | riser_bottom |
Lower limb pocket |
| 2 | grip |
Pivot point of the grip (usually hidden by the hand) |
| 3 | limb_tip_top |
String groove on a recurve; cam axle on a compound |
| 4 | limb_tip_bottom |
|
| 5 | stab_mount |
Front stabilizer bushing on the riser |
| 6 | front_rod_tip |
End of the long rod's weight or damper |
| 7 | rear_mount |
V-bar (Olympic) or back-bar bracket (compound) |
| 8, 9 | side_rod_tip (×2) |
Rear rod tips |
Barebows have no stabilizer points, and compounds often have a single rear rod. The model reports parts a bow doesn't have as absent (low confidence).
The two rear rod tips share one output channel. Which one is on the archer's left usually can't be told from a single image, so the model returns up to two peaks and leaves left/right to the application, which knows the camera position and the archer's handedness.
Files
| File | Precision | Size |
|---|---|---|
bowpose_fp32.onnx |
float32 | 47.6 MB |
bowpose_fp16.onnx |
float16 weights, float32 input/output | 23.8 MB |
bowpose_int8.onnx |
8-bit (static QDQ, last layer float) | 12.0 MB |
bowpose.json |
Keypoint and channel names, preprocessing | |
export_report.md |
Size, accuracy and CPU time of each file |
All three models have the same interface. fp16 is as accurate as fp32 at half the size. int8 is slightly less accurate and about 20% faster on a CPU.
Accuracy
Measured on synthetic validation renders (scenes held out from training), not on real video. Errors are in pixels on 640-pixel-wide images. A keypoint counts as missed when the model's confidence is under 0.3 for a part that's on the bow and in frame.
| Model | Median error | Within 5 px | Within 10 px | Missed | False stabilizer* | CPU time** |
|---|---|---|---|---|---|---|
| fp32 | 1.66 px | 84.9% | 93.3% | 1.5% | 12.9% | 20 ms |
| fp16 | 1.66 px | 84.9% | 93.3% | 1.5% | 12.9% | 20 ms |
| int8 | 1.69 px | 84.3% | 93.3% | 1.4% | 12.7% | 16 ms |
* How often a stabilizer point is reported on a bow that doesn't have that part, such as a barebow, averaged over the stabilizer points. ** One image with ONNX Runtime on the CPU of the cloud server used for training. Times vary by machine.
By keypoint (PyTorch model after the final epoch, which scored within 0.1 point of the released checkpoint; all 4,875 validation images):
| Keypoint | Median error | Within 10 px | Missed | False positive* |
|---|---|---|---|---|
riser_top |
1.41 px | 97% | 0.0% | |
riser_bottom |
1.64 px | 96% | 0.0% | |
grip |
1.68 px | 98% | 0.0% | |
limb_tip_top |
1.34 px | 97% | 0.0% | |
limb_tip_bottom |
1.64 px | 91% | 0.0% | |
stab_mount |
1.57 px | 99% | 0.2% | 6.9% |
front_rod_tip |
1.33 px | 92% | 0.4% | 6.2% |
rear_mount |
2.22 px | 97% | 0.2% | 6.9% |
side_rod_tip (×2) |
2.4 px | 77% | 9% | 19% |
* Reported on bows without that part.
The rear rod tips are the weakest points. They're thin, often point toward the camera, and are easily hidden by the archer's body.
Input and output
- Input:
image, float321×3×288×384(RGB, letterboxed to 384×288, ImageNet-normalized: mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]). - Output:
heatmaps, float321×9×72×96(stride 4). Channels 0–7 are keypoints 0–7; channel 8 holds both rear rod tips. - Decoding:
- For each channel, take the peak and refine it below one cell with a parabola fitted to the log of the heatmap.
- For channel 8, take the two strongest peaks after 5×5 non-maximum suppression.
- Map peak (cx, cy) to input pixels as (4·cx + 1.5, 4·cy + 1.5), then undo the letterbox.
- Treat the peak value as the confidence; around 0.3 is a reasonable threshold.
Model
A ResNet-18 backbone (ImageNet-pretrained) with a small feature-pyramid decoder, producing heatmaps at a stride of 4. It was trained for 25 epochs on about 95,000 images, with batch size 96 and AdamW with cosine decay, on one H100 in about 26 minutes. The checkpoint from epoch 22 scored best.
Training data
The model is trained only on synthetic images; no real photos or video were used. The images were rendered in Blender (Eevee and Cycles) and randomized:
- Archers: realistic human bodies from MPFB (MakeHuman for Blender) and simpler procedural bodies, adults and juniors, right- and left-handed. Bow sizes match the archer. About half the scenes are at anchor; the rest cover setup, drawing, follow-through and resting.
- Bows: Olympic recurve, barebow and compound, with random colours and accessories: sights, clickers, plungers, V-bars, side rods, dampers, quivers, cams.
- Settings: outdoor ranges, indoor halls and home or garage spaces, with varied lighting.
- Cameras: side, top and rear views like a multi-camera archery setup, plus random angles.
- Training augmentation: camera-like effects such as lens distortion, blur, noise, compression, white balance and occlusion.
Limitations
- The accuracy figures above are on synthetic images. Synthetic-only training means some accuracy loss on real video is expected, especially with unusual equipment, extreme lighting or heavy motion blur.
- Rear rods are the least reliable points, and the model sometimes reports them, or other stabilizer parts, on bows that don't have them.
- Hunting-style compounds with only a short front stabilizer are under-represented in the training data.
- It assumes one main archer per frame; other bows in the background can draw predictions.
- Left and right rear rods are not distinguished (see Keypoints).
Licence
CC-BY-4.0. You may use, share and adapt the model, including commercially, with credit to the author.