#!/usr/bin/env python3 """ Test template matching on 10-minute segment (38:40-48:40). v3 baseline shows 13 plays in this segment. This test verifies: 1. Template matching detects >= 13 plays (no regression) 2. Significant speed improvement over OCR Usage: cd /Users/andytaylor/Documents/Personal/cfb40 source .venv/bin/activate python tests/test_digit_templates/test_full_segment.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" # 10-minute test segment: 38:40 to 48:40 START_TIME = 38 * 60 + 40 # 2320 seconds END_TIME = 48 * 60 + 40 # 2920 seconds # v3 baseline: 13 plays in this segment EXPECTED_MIN_PLAYS = 13 # v3 baseline OCR time for 10 min would be ~52s (based on 312.7s for full video) # Target: < 20s for template matching (including template building) TARGET_TIME = 20.0 def test_full_segment(): """Test template matching on 10-minute segment.""" logger.info("=" * 60) logger.info("TEST: 10-Minute Segment (38:40-48:40)") 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 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=400, # Use first 400 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 plays (v3 baseline): >= %d", EXPECTED_MIN_PLAYS) # 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 (%.1f%%)", result.frames_with_scorebug, 100 * result.frames_with_scorebug / max(1, result.total_frames_processed)) logger.info(" Frames with clock: %d (%.1f%%)", result.frames_with_clock, 100 * result.frames_with_clock / max(1, result.total_frames_processed)) logger.info(" Plays detected: %d", len(result.plays)) # Timing analysis total_time = sum(result.timing.values()) template_building_time = result.timing.get("template_building", 0) template_matching_time = result.timing.get("template_matching", 0) ocr_time = result.timing.get("playclock_ocr", 0) logger.info("\nTiming breakdown:") for key, value in result.timing.items(): if value > 0: pct = 100 * value / total_time if total_time > 0 else 0 logger.info(" %s: %.2fs (%.1f%%)", key, value, pct) logger.info(" TOTAL: %.2fs", total_time) # Speed comparison # v3 baseline OCR time estimate for 10 min segment # Full video (8777s) took 312.7s for OCR, so 10 min (600s) would take ~21.4s for OCR alone estimated_ocr_time = 312.7 * (END_TIME - START_TIME) / 8777 actual_clock_time = template_building_time + template_matching_time + ocr_time logger.info("\nSpeed comparison:") logger.info(" Estimated OCR-only time (v3): %.1fs", estimated_ocr_time) logger.info(" Actual clock reading time: %.1fs", actual_clock_time) if actual_clock_time > 0: speedup = estimated_ocr_time / actual_clock_time logger.info(" Speedup: %.1fx", speedup) # List all plays logger.info("\nDetected 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") logger.info(" Play #%d: %.1fs - %.1fs (%.1fs) [%s]", play.get("play_number", 0), play_time, play.get("end_time", 0), duration, play_type) # Check success criteria plays_ok = len(result.plays) >= EXPECTED_MIN_PLAYS time_ok = total_time <= TARGET_TIME logger.info("\n" + "=" * 60) logger.info("TEST SUMMARY") logger.info("=" * 60) logger.info("Plays detected: %d (target: >= %d) - %s", len(result.plays), EXPECTED_MIN_PLAYS, "PASS" if plays_ok else "FAIL") logger.info("Processing time: %.2fs (target: <= %.1fs) - %s", total_time, TARGET_TIME, "PASS" if time_ok else "FAIL") passed = plays_ok # Only require play count, time is informational if passed: logger.info("\nTEST: PASSED") else: logger.info("\nTEST: FAILED") return passed if __name__ == "__main__": success = test_full_segment() sys.exit(0 if success else 1)