Skip to content

Latest commit

 

History

History
215 lines (169 loc) · 7.69 KB

File metadata and controls

215 lines (169 loc) · 7.69 KB

ShotTracker Project Status

Last Updated: February 12, 2026 Current Phase: ML pipeline functional, classifier tuned, needs retest + decide next milestone


Architecture Overview

mobile/          # Expo React Native app (partially built)
worker/          # Python ML pipeline (functional)
  app/ml/
    detector.py      # YOLODetector - object detection + tracking
    tracker.py       # TrajectoryTracker - ball path + velocity + interpolation
    classifier.py    # TrajectoryClassifier - state machine + hybrid 4-signal scoring
    pipeline.py      # Main pipeline - wires everything together
backend/         # FastAPI backend (scaffolding)
supabase/        # Supabase config (auth + DB)

What's Built

ML Pipeline (worker/) - FUNCTIONAL

Model: runs/detect/basketball_small_1280_v2/weights/best.pt

  • YOLO v26s, 1280px input resolution
  • 5 classes: ball, human, rim, made, shoot
  • Trained 20 epochs on ~27,200 images (original 23k + Roboflow 9.4k merged)
  • mAP50: 0.846 | mAP50-95: 0.590

Detection + Tracking:

  • BoT-SORT tracking via basketball_tracker.yaml
  • Rim-crop detection: 2x zoom inference at 640px around rim area
  • YOLO "made" class detection with 0.25 min confidence threshold
  • Retroactive "made" correction (30-frame window after shot resolution)
  • Ball trajectory interpolation for lost frames (physics-based prediction)

Shot Classification (State Machine):

IDLE -> APPROACH -> RIM_CONTACT -> RESOLUTION -> (make/miss)

Key features:

  • Pose-triggered + ball-triggered shot detection
  • Pose override for stale approaches
  • Ball departure confirmation (prevents false rim contact from shooter overlap)
  • Rim zone entry gate (3+ consecutive frames required)
  • Minimum flight time for ball-triggered approaches (30 frames)
  • Airball detection (pose-triggered approach that times out)

4-Signal Hybrid Classification:

Signal Side Weight Behind Weight What It Measures
S1: Line Intersection 0.30 0.15 Does ball path cross through rim?
S2: Scoring Zone 0.25 0.30 Ball in net area moving downward?
S3: Trajectory Prediction 0.15 0.30 Predicted arc + occlusion detection
S4: Net Interaction 0.30 0.25 Horizontal drift/velocity after exit

Additional classification logic:

  • S1 veto: if ball clearly misses rim, cap score below threshold
  • No-occlusion penalty: ball visible entire time near rim = likely miss
  • Re-entry penalty: ball bouncing back into rim zone = miss signal
  • Exit penalties: left/right exit = -0.30, above exit = auto-miss
  • YOLO "made" class override (if detected during shot = make)
  • Threshold: 0.45

Mobile App (mobile/) - PARTIALLY BUILT

  • Expo React Native with NativeWind (Tailwind CSS)
  • Some screens/features functional, others TODO

Backend (backend/) - SCAFFOLDING

  • FastAPI structure exists
  • Supabase integration configured (auth + DB)

Test Results (Pre-Tuning Baseline)

Tested on 4 videos recorded Feb 9, 2026. Results measured BEFORE latest classifier tuning (S1 veto, no-occlusion penalty, rim zone gate, etc.):

Video Camera Setup Shots Detected Correct Accuracy
Feb9SideAngle1 Side, tripod, ~25ft 7 (2M/5m) 6/7 6/6 86%
Feb9SideAngle2 Side, tripod, ~25ft 7 (2M/5m) 7/7 6/7 86%
Feb9SideGround1 Side, ground level 5 (2M/3m) 4/5 3/4 60%
Feb9FrontAngle1 Front/behind, elevated 11 (3M/8m) 10/11 7/10 64%
Total 30 27/30 22/27 81% on detected

Overall: 22/30 = 73% (including undetected shots)

Error Breakdown

  • 3 undetected shots - state machine never triggered (shot detection problem)
  • 2 heuristic false positives - misses classified as makes (FrontAngle1)
  • 2 heuristic false negatives - makes classified as misses (SideAngle2, FrontAngle1)
  • 1 timing issue - "made" class fired after shot already resolved (fixed by retroactive correction)

Camera Compatibility (Qualitative)

Setup Quality Notes
Side angle, tripod, 20-30ft Works well Best accuracy, clear ball trajectory
Behind player, halfcourt Works well Good for different perspective
Side angle, ground level OK Tricky - shooter body overlaps rim zone
Front angle, ground level Tricky Ball trajectory harder to track

Note: Significant classifier improvements were made AFTER these tests (S1 veto, no-occlusion penalty, rim zone entry gate, departure confirmation, stricter ball trigger, airball detection). Accuracy likely improved but needs retesting.


Training Data

Split Images
Train ~21,800
Valid ~3,800
Test ~2,200
Total ~27,200

Sources: original basketball dataset (23k) + Roboflow basketball-bs0zc (9.4k, with "made" and "shoot" classes)


Key Files

worker/
  app/ml/
    detector.py          # YOLODetector (5 classes, rim-crop, BoT-SORT)
    tracker.py           # TrajectoryTracker (interpolation, velocity)
    classifier.py        # TrajectoryClassifier (state machine + 4-signal hybrid)
    pipeline.py          # Main processing pipeline
  runs/detect/
    basketball_small_1280_v2/weights/best.pt   # Current model (v26s, 5 classes)
  data/combined/         # Merged training data (~27k images)
  data/basketball_made/  # Roboflow "made" dataset (source)
  tools/
    remap_roboflow_classes.py  # Class ID remapping script
  basketball_tracker.yaml      # BoT-SORT config
  test_classifier_debug.py     # Main testing script

Session History

Feb 12, 2026

  • Evaluated CNN rim-crop classifier approach (decided to defer)
  • Updated project status documentation
  • Planning next milestone

Feb 9-11, 2026

  • Added "made" + "shoot" classes to YOLO model via Roboflow dataset merge
  • Trained YOLO v26s v2 model (20 epochs, ~27k images, RTX 4070)
  • Integrated YOLO "made" class into classifier with confidence threshold (0.25)
  • Added retroactive "made" correction (30-frame window)
  • Tested on 4 self-recorded videos: 81% accuracy on detected shots
  • Extensive classifier tuning:
    • S1 veto (line intersection can veto false makes)
    • No-occlusion penalty (ball visible = likely not a make)
    • Rim zone entry gate (3+ consecutive frames)
    • Ball departure confirmation (prevents shooter overlap triggers)
    • Minimum flight time for ball-triggered approaches
    • Stricter ball trigger (5 consecutive upward frames + bottom half)
    • Airball detection for pose-triggered timeouts
    • Pose override for stale approaches
    • Reduced cooldown from 90 to 35 frames

Feb 1, 2026

  • Started training yolo26n on combined dataset (23k images)
  • Added trajectory interpolation for lost ball frames
  • Lowered detection thresholds
  • Completed pipeline integration with real components
  • Created deployment plan

Jan 29, 2026

  • Tried retraining with yolo26l - didn't improve ball tracking
  • Ball detection rate: ~42% during shots

Earlier Sessions

  • Built YOLODetector, TrajectoryTracker, TrajectoryClassifier
  • Trained initial model on 9,522 images
  • Rim detection: 97%, Ball detection: 42%

Deployment Plan

Phase 1: MVP on DigitalOcean CPU

  • Use $200 student credits
  • $6-12/mo droplet for FastAPI + Redis
  • yolo26s for video processing
  • Free for 16-33 months

Phase 2: Upgrade to GPU if needed

  • TensorDock GPU ($0.10/hr)
  • Processing time drops significantly
  • Cost: ~$1-5/mo

Cost Summary

Service Cost
DigitalOcean $0 (credits)
Supabase $0 (free tier)
Apple Developer $99/yr
Total MVP ~$100/yr

Possible GPU/CPU Costs

CPU: DigitalOcean ($200 student credits), Azure credits

GPU: Vast.ai, TensorDock, Runpod