docs: comprehensive README with architecture, usage, research references
Browse files
README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# πΈ Racquet Sports Video Analyzer
|
| 2 |
+
|
| 3 |
+
**PBVision / SwingVision style AI analysis for any racquet sport video.**
|
| 4 |
+
|
| 5 |
+
Automatically detects rallies, tracks players, classifies shots, and generates complete player performance profiles β from any video angle (portrait or landscape).
|
| 6 |
+
|
| 7 |
+
## Supported Sports
|
| 8 |
+
| Sport | Ball Tracking | Shot Types | Court Detection |
|
| 9 |
+
|-------|:---:|:---:|:---:|
|
| 10 |
+
| πΈ Badminton | β
| 15 types (smash, drop, clear, ...) | β
|
|
| 11 |
+
| πΎ Tennis | β
| 12 types (forehand, backhand, serve, ...) | β
|
|
| 12 |
+
| π₯ Pickleball | β
| 11 types (dink, third-shot-drop, erne, ...) | β
|
|
| 13 |
+
| π Padel | β
| 11 types (bandeja, vibora, bajada, ...) | β
|
|
| 14 |
+
|
| 15 |
+
## What It Does
|
| 16 |
+
|
| 17 |
+
```
|
| 18 |
+
INPUT: Any racquet sport video (phone recording, broadcast, GoPro)
|
| 19 |
+
β
|
| 20 |
+
ββββββββββββββββββββββββββββββββββββββββββββ
|
| 21 |
+
β Court Detection (lines, net, homography)β
|
| 22 |
+
β Player Detection + Tracking (YOLO11) β
|
| 23 |
+
β Ball/Shuttle Tracking (CV + Kalman) β
|
| 24 |
+
β Hit Detection (ball reversal + wrist) β
|
| 25 |
+
β Rally Segmentation (temporal grouping) β
|
| 26 |
+
β Shot Classification (VideoMAE) β
|
| 27 |
+
β Player Analytics (movement, shots, etc) β
|
| 28 |
+
ββββββββββββββββββββββββββββββββββββββββββββ
|
| 29 |
+
β
|
| 30 |
+
OUTPUT:
|
| 31 |
+
πΌ Annotated video with overlays
|
| 32 |
+
π JSON report with full match analysis
|
| 33 |
+
πΊοΈ Player movement heatmaps
|
| 34 |
+
π€ Player profiles (playstyle, strengths/weaknesses)
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
## Quick Start
|
| 38 |
+
|
| 39 |
+
### 1. Install
|
| 40 |
+
```bash
|
| 41 |
+
pip install -r requirements.txt
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
### 2. Run on your video
|
| 45 |
+
```bash
|
| 46 |
+
# Auto-detect sport, GPU mode
|
| 47 |
+
python run_analysis.py --video match.mp4
|
| 48 |
+
|
| 49 |
+
# Specify sport + output dir
|
| 50 |
+
python run_analysis.py --video match.mp4 --sport badminton --output ./my_analysis
|
| 51 |
+
|
| 52 |
+
# Portrait video from phone (pickleball at the park)
|
| 53 |
+
python run_analysis.py --video phone_recording.mp4 --sport pickleball
|
| 54 |
+
|
| 55 |
+
# CPU mode (slower but works everywhere)
|
| 56 |
+
python run_analysis.py --video match.mp4 --device cpu
|
| 57 |
+
|
| 58 |
+
# Fast mode: skip frames + no shot classification
|
| 59 |
+
python run_analysis.py --video match.mp4 --frame-skip 2 --no-shot-classification
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
### 3. Python API
|
| 63 |
+
```python
|
| 64 |
+
from racquet_sports_analyzer import RacquetSportsAnalyzer, PipelineConfig, Sport
|
| 65 |
+
|
| 66 |
+
config = PipelineConfig().for_sport(Sport.BADMINTON)
|
| 67 |
+
analyzer = RacquetSportsAnalyzer(config)
|
| 68 |
+
results = analyzer.analyze("match.mp4", output_dir="./output")
|
| 69 |
+
|
| 70 |
+
# Access results
|
| 71 |
+
print(f"Rallies: {results['match_summary']['total_rallies']}")
|
| 72 |
+
for pid, profile in results['player_profiles'].items():
|
| 73 |
+
print(f"Player {pid}: {profile['playstyle']} β {profile['rally']['win_rate']:.0%} win rate")
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
## Output: Player Profile Example
|
| 77 |
+
|
| 78 |
+
```
|
| 79 |
+
==================================================
|
| 80 |
+
PLAYER 1 PROFILE
|
| 81 |
+
==================================================
|
| 82 |
+
Side: Near/Top
|
| 83 |
+
Playstyle: AGGRESSIVE
|
| 84 |
+
Time tracked: 142.3s (4269 frames)
|
| 85 |
+
|
| 86 |
+
π MOVEMENT
|
| 87 |
+
Distance: 48523px (89.2m)
|
| 88 |
+
Avg speed: 341 px/s (6.3 m/s)
|
| 89 |
+
Max speed: 1205 px/s (22.1 m/s)
|
| 90 |
+
Coverage: 67.2%
|
| 91 |
+
Dominant side: balanced
|
| 92 |
+
Idle time: 18.4%
|
| 93 |
+
|
| 94 |
+
πΈ SHOTS
|
| 95 |
+
Total: 47
|
| 96 |
+
Favorite: smash
|
| 97 |
+
smash: 31.9%
|
| 98 |
+
clear: 21.3%
|
| 99 |
+
drop: 17.0%
|
| 100 |
+
|
| 101 |
+
π― RALLY PERFORMANCE
|
| 102 |
+
Played: 23
|
| 103 |
+
Won: 15 | Lost: 8
|
| 104 |
+
Win rate: 65%
|
| 105 |
+
Avg length when winning: 4.2 shots
|
| 106 |
+
Avg length when losing: 7.1 shots
|
| 107 |
+
|
| 108 |
+
πͺ BIOMECHANICS
|
| 109 |
+
Max wrist speed: 28.4 px/frame
|
| 110 |
+
Avg elbow angle: 142.3Β°
|
| 111 |
+
|
| 112 |
+
π PLAYSTYLE BREAKDOWN
|
| 113 |
+
aggressive ββββββββββββββββββββ 62.5%
|
| 114 |
+
counter-puncher ββββββββββββββββββββ 15.0%
|
| 115 |
+
all-round ββββββββββββββββββββ 12.5%
|
| 116 |
+
defensive ββββββββββββββββββββ 10.0%
|
| 117 |
+
|
| 118 |
+
β
STRENGTHS
|
| 119 |
+
β’ Excellent court coverage
|
| 120 |
+
β’ Explosive court speed
|
| 121 |
+
β’ Strong smash
|
| 122 |
+
β’ Diverse shot selection
|
| 123 |
+
β’ High win rate (65%)
|
| 124 |
+
β’ 3 first-shot winners
|
| 125 |
+
β οΈ WEAKNESSES
|
| 126 |
+
β’ Struggles in long rallies
|
| 127 |
+
==================================================
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
## Architecture Deep Dive
|
| 131 |
+
|
| 132 |
+
### Models Used
|
| 133 |
+
|
| 134 |
+
| Component | Model | Source | Purpose |
|
| 135 |
+
|-----------|-------|--------|---------|
|
| 136 |
+
| Player Detection + Tracking | YOLO11n-pose + ByteTrack | [ultralytics](https://github.com/ultralytics/ultralytics) | Real-time person detection with pose keypoints |
|
| 137 |
+
| Ball Tracking | Classical CV + Kalman Filter | Built-in | Motion + color + shape filtering for ball detection |
|
| 138 |
+
| Shot Classification | VideoMAE-base | [MCG-NJU/videomae-base](https://huggingface.co/MCG-NJU/videomae-base) | 16-frame clip β shot type label |
|
| 139 |
+
| Pose (high-accuracy) | ViTPose+ | [usyd-community/vitpose-base-simple](https://huggingface.co/usyd-community/vitpose-base-simple) | COCO-17 keypoint estimation (optional upgrade) |
|
| 140 |
+
|
| 141 |
+
### Pipeline Flow (per frame)
|
| 142 |
+
|
| 143 |
+
```python
|
| 144 |
+
# 1. Court Detection (every 30 frames)
|
| 145 |
+
court = court_detector.detect(frame) # lines, net, homography
|
| 146 |
+
|
| 147 |
+
# 2. Player Detection + Tracking
|
| 148 |
+
players = player_detector.detect_and_track(frame) # YOLO11 + ByteTrack
|
| 149 |
+
# β track_id, bbox, center, feet_position, keypoints(17Γ2)
|
| 150 |
+
|
| 151 |
+
# 3. Ball Tracking
|
| 152 |
+
ball = ball_tracker.track(frame) # BG subtraction + color + Kalman
|
| 153 |
+
# β position, velocity, radius, confidence
|
| 154 |
+
|
| 155 |
+
# 4. Hit Detection (dual signal fusion)
|
| 156 |
+
ball_hit = ball_tracker.detect_hit_event() # ball direction reversal
|
| 157 |
+
wrist_swing = player_detector.detect_swing(track_id) # wrist velocity spike
|
| 158 |
+
hit_confirmed = ball_hit OR wrist_swing # fused signal
|
| 159 |
+
|
| 160 |
+
# 5. Rally Detection
|
| 161 |
+
rally = rally_detector.process_frame( # temporal grouping
|
| 162 |
+
ball_hit, ball_position, players, wrist_swings
|
| 163 |
+
)
|
| 164 |
+
# β rally start/end, shot count, serve team, winner
|
| 165 |
+
|
| 166 |
+
# 6. Shot Classification (on hit events)
|
| 167 |
+
if hit_confirmed:
|
| 168 |
+
clip = shot_classifier.extract_hit_clip(frames, hit_frame) # 3 pre + 12 post
|
| 169 |
+
shot_type = shot_classifier.classify_from_frames(clip)
|
| 170 |
+
# β "smash", "drop", "clear", etc.
|
| 171 |
+
|
| 172 |
+
# 7. Analytics (post-processing)
|
| 173 |
+
for player in tracked_players:
|
| 174 |
+
profile = analytics.analyze_player(track_history, rallies)
|
| 175 |
+
# β movement, shots, rally stats, biomechanics, playstyle
|
| 176 |
+
```
|
| 177 |
+
|
| 178 |
+
### Research Foundation
|
| 179 |
+
|
| 180 |
+
This system is built on these SOTA papers:
|
| 181 |
+
|
| 182 |
+
| Paper | What We Use | Citation |
|
| 183 |
+
|-------|------------|----------|
|
| 184 |
+
| **TOTNet** | Ball tracking architecture (3D conv U-Net + optical flow) | [arxiv:2508.09650](https://arxiv.org/abs/2508.09650) |
|
| 185 |
+
| **WASB** | Multi-sport ball detection baseline (HRNet) | [arxiv:2311.05237](https://arxiv.org/abs/2311.05237) |
|
| 186 |
+
| **BST** | Shot classification strategy (hit-centered clips + skeleton + trajectory) | [arxiv:2502.21085](https://arxiv.org/abs/2502.21085) |
|
| 187 |
+
| **BFMD** | Full pipeline design (YOLOX + OC-SORT + TrackNetV2 + VideoMAE) | [arxiv:2603.25533](https://arxiv.org/abs/2603.25533) |
|
| 188 |
+
| **ByteTrack** | Player tracking (associates all detection boxes incl. low-score) | [arxiv:2110.06864](https://arxiv.org/abs/2110.06864) |
|
| 189 |
+
| **GTA** | Tracklet post-processing for long videos | [arxiv:2411.08216](https://arxiv.org/abs/2411.08216) |
|
| 190 |
+
| **VideoMAE** | Action recognition backbone for shot classification | [arxiv:2203.12602](https://arxiv.org/abs/2203.12602) |
|
| 191 |
+
| **ViTPose+** | High-accuracy pose estimation (81.1 AP on COCO) | [arxiv:2212.04246](https://arxiv.org/abs/2212.04246) |
|
| 192 |
+
|
| 193 |
+
## Improving Accuracy
|
| 194 |
+
|
| 195 |
+
### Level 1: Out-of-the-box (this repo)
|
| 196 |
+
- Classical ball tracking + YOLO detection + zero-shot VideoMAE
|
| 197 |
+
- Good for: quick analysis, recreational play, phone recordings
|
| 198 |
+
|
| 199 |
+
### Level 2: Fine-tune shot classifier
|
| 200 |
+
```python
|
| 201 |
+
from racquet_sports_analyzer.shot_classifier import ShotClassifierTrainer
|
| 202 |
+
|
| 203 |
+
trainer = ShotClassifierTrainer(sport=Sport.BADMINTON)
|
| 204 |
+
trainer.train(
|
| 205 |
+
train_clips=my_labeled_clips, # list of (16_frames, label_idx)
|
| 206 |
+
val_clips=my_val_clips,
|
| 207 |
+
output_dir="./shot_model_badminton",
|
| 208 |
+
epochs=30,
|
| 209 |
+
batch_size=16,
|
| 210 |
+
push_to_hub=True,
|
| 211 |
+
hub_model_id="your-username/shot-classifier-badminton",
|
| 212 |
+
)
|
| 213 |
+
```
|
| 214 |
+
- Use ShuttleSet (36K labeled strokes) for badminton
|
| 215 |
+
- Use TenniSet (3.5K strokes) for tennis
|
| 216 |
+
- For pickleball/padel: collect and label 30-50 matches
|
| 217 |
+
|
| 218 |
+
### Level 3: Train deep ball tracker (TOTNet/WASB)
|
| 219 |
+
- Replace classical CV ball tracker with trained neural network
|
| 220 |
+
- Download TrackNetV2 dataset (26 badminton matches, NCTU)
|
| 221 |
+
- Train TOTNet: `github.com/AugustRushG/TOTNet`
|
| 222 |
+
- Or WASB: `github.com/nttcom/WASB-SBDT`
|
| 223 |
+
- Set `config.ball_tracking.method = "tracknet"` and provide model path
|
| 224 |
+
|
| 225 |
+
### Level 4: ViTPose+ for biomechanics
|
| 226 |
+
```python
|
| 227 |
+
config.pose.method = "vitpose"
|
| 228 |
+
config.pose.vitpose_checkpoint = "usyd-community/vitpose-plus-base"
|
| 229 |
+
# β Higher accuracy wrist/elbow tracking β better shot detection + biomechanics
|
| 230 |
+
```
|
| 231 |
+
|
| 232 |
+
## Hardware Requirements
|
| 233 |
+
|
| 234 |
+
| Mode | GPU | Speed | Quality |
|
| 235 |
+
|------|-----|-------|---------|
|
| 236 |
+
| CPU (laptop) | None | ~2-5 fps | Good (no shot classification) |
|
| 237 |
+
| T4 (Colab) | 16GB | ~15-25 fps | Great |
|
| 238 |
+
| A10G/A100 | 24-80GB | ~30-60 fps | Full pipeline with all features |
|
| 239 |
+
|
| 240 |
+
**Recommended**: NVIDIA GPU with β₯16GB VRAM for real-time processing.
|
| 241 |
+
|
| 242 |
+
## Project Structure
|
| 243 |
+
|
| 244 |
+
```
|
| 245 |
+
racquet_sports_analyzer/
|
| 246 |
+
βββ __init__.py # Package exports
|
| 247 |
+
βββ config.py # All configuration (sport-specific params, model settings)
|
| 248 |
+
βββ court_detector.py # Court line detection + homography
|
| 249 |
+
βββ player_detector.py # YOLO11 + ByteTrack + pose keypoints
|
| 250 |
+
βββ ball_tracker.py # Classical CV + Kalman + TrackNet placeholder
|
| 251 |
+
βββ rally_detector.py # Rally segmentation from hit events
|
| 252 |
+
βββ shot_classifier.py # VideoMAE shot type classification + trainer
|
| 253 |
+
βββ analytics.py # Movement, shots, rally stats, biomechanics, playstyle
|
| 254 |
+
βββ pipeline.py # Main orchestrator (ties everything together)
|
| 255 |
+
|
| 256 |
+
run_analysis.py # CLI entry point
|
| 257 |
+
requirements.txt # Dependencies
|
| 258 |
+
```
|
| 259 |
+
|
| 260 |
+
## Key Design Decisions
|
| 261 |
+
|
| 262 |
+
1. **Modular pipeline over end-to-end**: Each component can be upgraded independently. Start with classical CV ball tracking, upgrade to TOTNet later. Start with YOLO-pose, upgrade to ViTPose+ later.
|
| 263 |
+
|
| 264 |
+
2. **Classical CV ball tracker as default**: Works on all sports without training. The TrackNet-style deep model is a placeholder β train it on your data for 10x better ball detection.
|
| 265 |
+
|
| 266 |
+
3. **Dual-signal hit detection**: Fuses ball direction reversal (from ball tracker) with wrist velocity spikes (from pose keypoints). Either signal alone has false positives; combined they're robust.
|
| 267 |
+
|
| 268 |
+
4. **Hit-frame-centered clips for shot classification**: The BST paper proved this is significantly better than fixed-width temporal windows. We extract 3 frames before + 12 frames after each hit for classification.
|
| 269 |
+
|
| 270 |
+
5. **Playstyle classification from multi-signal scoring**: Movement speed + shot distribution + rally patterns β weighted score across aggressive/defensive/all-round/counter-puncher archetypes.
|
| 271 |
+
|
| 272 |
+
## Datasets for Training
|
| 273 |
+
|
| 274 |
+
| Dataset | Sport | Size | Where |
|
| 275 |
+
|---------|-------|------|-------|
|
| 276 |
+
| ShuttleSet | Badminton | 44 matches, 36K strokes | [shuttleset.badminton.tw](https://shuttleset.badminton.tw/) |
|
| 277 |
+
| TrackNetV2 | Badminton | 26 matches (ball annotations) | [NCTU repo](https://nol.cs.nctu.edu.tw/ndo/TrackNet/) |
|
| 278 |
+
| BFMD | Badminton | 19 matches, 16K hits | [arxiv:2603.25533](https://arxiv.org/abs/2603.25533) |
|
| 279 |
+
| BadmintonDB | Badminton | 7.6K strokes, 8 matches | GitHub |
|
| 280 |
+
| TenniSet | Tennis | 3.5K strokes, 5 matches | BST paper authors |
|
| 281 |
+
| WASB | Multi-sport | 5 datasets | [github.com/nttcom/WASB-SBDT](https://github.com/nttcom/WASB-SBDT) |
|
| 282 |
+
|
| 283 |
+
**β οΈ Pickleball & Padel**: No public academic datasets exist. You'll need to collect and label your own data. This is a competitive moat opportunity.
|
| 284 |
+
|
| 285 |
+
## License
|
| 286 |
+
|
| 287 |
+
MIT
|
| 288 |
+
|
| 289 |
+
## Citation
|
| 290 |
+
|
| 291 |
+
If you use this in your work:
|
| 292 |
+
```
|
| 293 |
+
@software{racquet_sports_analyzer,
|
| 294 |
+
title={Racquet Sports Video Analyzer},
|
| 295 |
+
year={2026},
|
| 296 |
+
url={https://huggingface.co/Bot-Derpy/racquet-sports-analyzer}
|
| 297 |
+
}
|
| 298 |
+
```
|