cfb40 / scripts /test_missed_play.py
andytaylor-smg's picture
adding sys back in when calls sys.exit
1386d71
#!/usr/bin/env python3
"""
Test that Play #136 at 1:52:06 (6726.5s) is detected with template matching.
This play was noted in missed_plays_analysis.md as being missed in some scenarios.
The v3 baseline shows it was detected at 6726.5s.
This test verifies the template matching pipeline can detect this play.
Usage:
cd /Users/andytaylor/Documents/Personal/cfb40
source .venv/bin/activate
python tests/test_digit_templates/test_missed_play.py
"""
import logging
import sys
from pathlib import Path
from pipeline.play_detector import PlayDetector, DetectionConfig
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
# Test configuration
VIDEO_PATH = "full_videos/OSU vs Tenn 12.21.24.mkv"
TEMPLATE_PATH = "output/OSU_vs_Tenn_12_21_24_template.png"
PLAYCLOCK_CONFIG_PATH = "output/OSU_vs_Tenn_12_21_24_playclock_config.json"
# Segment around the missed play (6680s - 6800s = ~2 minutes)
# Play #136 should be at ~6726.5s
START_TIME = 6680 # 1:51:20
END_TIME = 6800 # 1:53:20
# Expected play time from v3 baseline
EXPECTED_PLAY_TIME = 6726.5
TOLERANCE = 5.0 # Allow 5 second tolerance
def test_missed_play_detection():
"""Test that Play #136 at 6726.5s is detected with template matching."""
logger.info("=" * 60)
logger.info("TEST: Missed Play Detection (1:52:06 / 6726.5s)")
logger.info("=" * 60)
# Check files exist
for path, name in [(VIDEO_PATH, "Video"), (TEMPLATE_PATH, "Template"), (PLAYCLOCK_CONFIG_PATH, "Config")]:
if not Path(path).exists():
logger.error("%s not found: %s", name, path)
return False
# Create detection config with template matching enabled
config = DetectionConfig(
video_path=VIDEO_PATH,
template_path=TEMPLATE_PATH,
clock_region_config_path=PLAYCLOCK_CONFIG_PATH,
start_time=START_TIME,
end_time=END_TIME,
frame_interval=0.5,
use_template_matching=True,
template_collection_frames=200, # Use first 200 frames for template building
)
logger.info("\nConfiguration:")
logger.info(" Segment: %.1fs - %.1fs (%.1f minutes)", START_TIME, END_TIME, (END_TIME - START_TIME) / 60)
logger.info(" Template matching: ENABLED")
logger.info(" Expected play at: %.1fs (±%.1fs)", EXPECTED_PLAY_TIME, TOLERANCE)
# Run detection
logger.info("\n[Step 1] Running detection pipeline...")
detector = PlayDetector(config)
# Set fixed region from known scorebug location
detector.scorebug_detector.set_fixed_region((128, 975, 1669, 46))
result = detector.detect()
# Analyze results
logger.info("\n[Step 2] Analyzing results...")
logger.info(" Total frames processed: %d", result.total_frames_processed)
logger.info(" Frames with scorebug: %d", result.frames_with_scorebug)
logger.info(" Frames with clock: %d", result.frames_with_clock)
logger.info(" Plays detected: %d", len(result.plays))
# Check timing breakdown
logger.info("\nTiming breakdown:")
for key, value in result.timing.items():
if value > 0:
logger.info(" %s: %.2fs", key, value)
total_time = sum(result.timing.values())
logger.info(" TOTAL: %.2fs", total_time)
# Check for the expected play
found_play = False
closest_play = None
closest_distance = float("inf")
for play in result.plays:
play_time = play.get("start_time", 0)
distance = abs(play_time - EXPECTED_PLAY_TIME)
if distance < closest_distance:
closest_distance = distance
closest_play = play
if distance <= TOLERANCE:
found_play = True
logger.info("\n✓ FOUND expected play at %.1fs (distance: %.1fs)", play_time, distance)
logger.info(" Play details: %s", play)
if not found_play:
logger.info("\n✗ Expected play at %.1fs NOT FOUND within tolerance", EXPECTED_PLAY_TIME)
if closest_play:
logger.info(" Closest play: %.1fs (distance: %.1fs)", closest_play.get("start_time", 0), closest_distance)
# List all detected plays
logger.info("\nAll detected plays:")
for play in result.plays:
play_time = play.get("start_time", 0)
duration = play.get("duration", 0)
play_type = play.get("play_type", "unknown")
marker = " <-- TARGET" if abs(play_time - EXPECTED_PLAY_TIME) <= TOLERANCE else ""
logger.info(" Play #%d: %.1fs - %.1fs (%.1fs) [%s]%s", play.get("play_number", 0), play_time, play.get("end_time", 0), duration, play_type, marker)
# Summary
logger.info("\n" + "=" * 60)
logger.info("TEST SUMMARY")
logger.info("=" * 60)
logger.info("Plays detected: %d", len(result.plays))
logger.info("Expected play found: %s", "YES" if found_play else "NO")
logger.info("Processing time: %.2fs", total_time)
if found_play:
logger.info("\nTEST: PASSED")
else:
logger.info("\nTEST: FAILED")
return found_play
if __name__ == "__main__":
success = test_missed_play_detection()
sys.exit(0 if success else 1)