Skip to content

Repository files navigation

AI-Powered Archery Score Detection

Automated archery scoring using computer vision and YOLO26 object detection.

This project transitions archery scoring from manual logging to a high-precision, automated pipeline. It captures and analyzes target face images to detect arrow placements and calculate scores in real-time, bridging traditional sport with modern data analytics for both high-volume training sessions and professional tournaments.

For full methodology, architecture details, and complete breakdowns → read the blog post.


Table of Contents


Project Vision and Scope

The core objective is automation of the scoring pipeline. Traditionally, archers must walk to the target and manually record scores, a process prone to human error and fatigue. This system allows users to simply photograph the target; the AI identifies the arrows and computes their values instantly.

Target-Agnostic Design

The MVP focuses on World Archery (WA) outdoor target faces (122cm and 80cm) using the standard 10-zone scoring system. However, the architectural logic is target-agnostic: by identifying universal structural markers rather than predicting static scores, the system is designed for seamless adaptation to:

  • Indoor Archery: Triple-spot or 40cm faces
  • Custom Targets: Proprietary club or training faces

Data Engineering and Methodology

Data Sourcing and Curation

I aggregated a raw pool of 3,700 images from four specialized repositories on Roboflow:

  • archery-skmsa/archery
  • uni-oidi4/archery
  • archery-scoring/Archery Scoring
  • shrutiharshil/DJS Phoenix

After a rigorous filtering phase (discarding low-resolution frames, redundant images, and poorly labeled samples) I produced a refined set of 250 high-variance images for fine-tuning.

Geometric Pre-processing: Segmentation to Detection

Several classes (notably arrow_shaft) were originally labeled as polygons (segmentation) rather than bounding boxes. A custom Python script converts these by calculating the extreme polygon coordinates $(x_{\min}, y_{\min}, x_{\max}, y_{\max})$ to derive the YOLO-compatible bounding box center $(c_x, c_y)$ and dimensions $(w, h)$.

Augmentation Strategy

Applied via Roboflow, expanding the training set to 525 images (70/20/10 split):

Augmentation Value Purpose
Horizontal Flip 50% probability Handles different approach angles
Brightness +/-25% Simulates outdoor lighting variation
Blur and Noise Applied Mimics low-quality sensors / motion blur

Labeling Strategy

Class Role
arrow_shaft Identifies arrow body; assists in distinguishing arrows from target lines
arrow_tip Primary scoring key -- precise point of impact
target_center Defines the absolute origin (0,0) of the target coordinate system
target_face 4-point detection for perspective correction

Class Distribution:

Class Count
arrow_shaft 2,742
arrow_tip 2,577
target_center 519
target_face 519

Archery target sample

Dataset hosted on Roboflow under archeryxpert-score-detection.


Model Architecture: YOLO26

This project uses YOLO26, the state-of-the-art in the YOLO family as of early 2026.

Key Architectural Advantages

Feature Detail
NMS-Free Direct end-to-end prediction -- no Non-Maximum Suppression latency
CPU Optimization Nano variant (YOLO26n) shows ~43% speed increase over YOLO11 on mobile CPUs
MuSGD Optimizer Muon-style optimization (adapted from LLMs) for stable convergence on small datasets

Dataset Structure

/images   -- image files
/labels   -- paired .txt files: class_id | cx | cy | w | h
data.yaml -- paths + class names: ['arrow_shaft', 'arrow_tip', 'target_center', 'target_face']

Training Hyperparameters

epochs: 100
imgsz: 640
batch: 16
optimizer: AdamW
lr0: 0.001
lrf: 0.01
warmup_epochs: 3
weight_decay: 0.0005
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
translate: 0.1
scale: 0.5
fliplr: 0.5
mosaic: 1.0
degrees: 0.0
dropout: 0.1
patience: 20
device: 0
workers: 2
cache: true

Key Decisions

  • AdamW over SGD: Better for small datasets; adapts learning rate per parameter automatically.
  • scale=0.5: Critical for archery -- archers photograph from varying distances, so an arrow tip can change dramatically in pixel size.
  • degrees=0.0: Rotation disabled because axis-aligned bounding boxes would become inaccurate for rotated objects.
  • mosaic=1.0: Combines 4 images into a 2x2 grid per training step, effectively quadrupling training variety.
  • patience=20: Early stopping prevents overfitting; training may stop well before epoch 100.

Performance Results and Analysis

Model Summary

YOLO26s summary (fused): 122 layers, 9,466,728 parameters, 0 gradients, 20.5 GFLOPs
Speed: 0.3ms preprocess, 5.3ms inference, 0.0ms loss, 1.0ms postprocess per image

Validation Set

Metric YOLO26s YOLOv12s
Overall mAP50 0.913 0.924
Overall mAP50-95 0.698 0.704
Precision 0.910 0.911
Recall 0.871 0.890

Per-Class mAP50:

Class YOLO26s YOLOv12s
arrow_shaft 0.914 0.948
arrow_tip 0.776 0.785
target_center 0.975 0.972
target_face 0.989 0.993

Test Set

Metric YOLO26s YOLOv12s
Overall mAP50 0.875 0.872
Overall mAP50-95 0.653 0.659
Precision 0.878 0.879
Recall 0.844 0.862

Per-Class mAP50:

Class YOLO26s YOLOv12s
arrow_shaft 0.909 0.901
arrow_tip 0.673 0.608
target_center 0.951 0.985
target_face 0.969 0.992

Why YOLO26s Was Selected

Factor YOLO26s YOLOv12s Winner
Val->Test mAP50 gap 0.038 0.053 YOLO26s (less overfitting)
Arrow tip mAP50 (test) 0.673 0.608 YOLO26s
Target center mAP50 (test) 0.951 0.985 YOLOv12s
Total inference time 6.3ms 13.4ms YOLO26s

Arrow tip detection is the critical failure mode for scoring accuracy. YOLO26s outperforms YOLOv12s on this class by +6.5 mAP50 points and is approximately 2x faster at inference. It was selected for production.

Failure Case Analysis

YOLO26s: 9/25 test images had missed arrow tips
YOLOv12s: 7/25 test images had missed arrow tips

Worst cases:

GT Arrows Detected Missed
5 1 4
6 4 2
6 4 2

The primary failure mode is dense clustering in the gold zone (5+ arrows). Images with fewer than 4 arrows showed near-perfect detection.

YOLO26s Failed Cases

Failed Cases YOLO26s

YOLOv12s Failed Cases

Failed Cases YOLOv12s


Scoring Logic and Integration Pipeline

Image -> Perspective Correction -> YOLO Detection -> Geometry Resolution -> Score Calculation -> Visualization

Project Structure

archery/
├── models/
│   └── best.pt
├── src/
│   ├── visualize_inference.py   # drawing results for single inference
│   ├── detection.py             # YOLO inference
│   ├── perspective.py           # HSV + ellipse + affine warp
│   ├── geometry.py              # distance calc + score lookup
│   └── visualize.py             # drawing results
├── main.py                      # entry point
├── labeling.py                  # auto-label new images using model
└── config.py                    # all constants and paths

The entire pipeline operates in pixel coordinates. Every module produces and consumes pixel-space values, eliminating the normalization mismatch common when mixing YOLO's 0-1 normalized outputs with pixel-space geometry.

Stage 1 -- Perspective Correction

Photographs are rarely taken head-on. Camera tilt causes the circular target to appear as an ellipse, compressing radial distances along the tilt axis. This stage warps the image to restore a circular target and geometrically accurate distances.

HSV Red Zone Isolation

The red scoring zone (rings 7-8) is isolated using two HSV hue ranges (red wraps the hue cylinder):

RED_HSV_LOWER_1 = (0,   80, 80)   # hue 0-10 degrees
RED_HSV_UPPER_1 = (10,  255, 255)

RED_HSV_LOWER_2 = (170, 80, 80)   # hue 170-180 degrees
RED_HSV_UPPER_2 = (180, 255, 255)

$S \geq 80$, $V \geq 80$ rejects noise pixels with incidental red-ish hue.

Morphological Cleanup: MORPH_CLOSE fills holes from arrow shafts crossing the red zone; MORPH_OPEN removes stray exterior pixels. Order matters: close first, then open.

Ellipse Fitting: The largest contour is selected and fitted via cv2.fitEllipse, returning center $(c_x, c_y)$, axes $(w, h)$, and rotation angle $\theta$.

Affine Warp: Three point correspondences map the detected ellipse to a circle using the parametric ellipse boundary:

$$x(t) = c_x + a\cos t \cos\phi - b\sin t \sin\phi$$ $$y(t) = c_y + a\cos t \sin\phi + b\sin t \cos\phi$$

Extrema are computed via:

$$t_y = \arctan2(b\cos\phi,\ a\sin\phi), \quad t_x = \arctan2(-b\sin\phi,\ a\cos\phi)$$

Point Source Destination
Top Ellipse top extremum $(c_x, c_y - r)$
Right Ellipse right extremum $(c_x + r, c_y)$
Bottom Ellipse bottom extremum $(c_x, c_y + r)$

Full Target Radius: The red zone covers 40% of the full target radius on WA 122cm targets:

$$R_{\text{full}} = \frac{r_{\text{red zone}}}{0.4}$$

Perspective Correction Steps

Stage 2 -- YOLO Detection

The model runs on the corrected image with conf=0.25, iou=0.45, max_det=20. All coordinates use box.xywh (pixel space). For target_face and target_center, only the highest-confidence detection is kept.

YOLO Detection Output

Stage 3 -- Geometry Resolution

Center and radius are resolved by fusing the HSV-based and YOLO-based sources:

Center priority: YOLO target_center -> ellipse center -> YOLO target_face center
Radius priority: Ellipse-based (scaled by RED_ZONE_RATIO) -> YOLO target_face width / 2

A cross-validation check warns if the two center sources diverge by more than 30 pixels.

Stage 4 -- Score Calculation

Tip Refinement: Each tip is refined using its nearest shaft (within 50px). A weighted blend uses detection confidence as the weight:

$$P_{\text{final}} = P_{\text{tip}} \cdot w + P_{\text{shaft}} \cdot (1 - w)$$

Distance Ratio:

$$\text{ratio} = \frac{\sqrt{(t_x - c_x)^2 + (t_y - c_y)^2}}{R_{\text{full}}}$$

WA 122cm Ring Table:

Ring Outer Edge Ratio Score
X 0.05 10
10 0.10 10
9 0.20 9
8 0.30 8
7 0.40 7
6 0.50 6
5 0.60 5
4 0.70 4
3 0.80 3
2 0.90 2
1 1.00 1
Miss > 1.0 0

Boundary Detection: Arrows within +/-0.015 of any ring edge are flagged is_boundary: true and highlighted in visualization for manual verification.

Stage 5 -- Visualization

  • Concentric ring overlays aligned to the resolved center
  • Arrow shaft bounding boxes (orange)
  • Scored tip markers colored by zone (gold -> red -> blue -> black -> white -> gray)
  • Cyan border on boundary-flagged arrows

Output Schema

{
    'image': 'filename.jpg',
    'arrows':[
        {'score': 10, 'ratio': 0.031, 'angle': 45.2, 'is_boundary': False,
         'x': 412.3, 'y': 438.1, 'confidence': 0.87},
        ...
    ],
    'total': 58,
    'arrow_count': 6,
    'boundaries': [3]   # indices of arrows near ring edges
}

Final Score Detection Output


Limitations and Known Issues

  • Dense clustering: Arrow tip detection degrades significantly when 5+ arrows cluster in the high-scoring zones.
  • Localization precision: mAP50-95 of 19.5% on arrow tips is insufficient for tournament-grade scoring without user confirmation on boundary arrows.
  • Dataset size: ~500 training images. Performance is expected to improve substantially with more diverse data, particularly close-up images of clustered arrows.
  • Perspective correction fragility: Small radius estimation errors from the red-zone ellipse propagate outward through each ring. The pipeline compensates by preferring the YOLO-detected target_center over the ellipse center, but full homography-based correction remains an open problem.

About

A computer vision pipeline that detects arrows and scores an archery target automatically.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages