#!/usr/bin/env python3 """ Compare playclock regions between working and non-working timestamps. This will help us understand why clock readings work at some timestamps but not others. """ import json import logging import sys from pathlib import Path import cv2 import numpy as np # Add src to path sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from readers import ReadPlayClock from setup import DigitTemplateLibrary from video import iter_frames_ffmpeg from utils.regions import preprocess_playclock_region logging.basicConfig(level=logging.INFO, format="%(message)s") logger = logging.getLogger(__name__) # Video path VIDEO_PATH = Path("/Users/andytaylor/Documents/Personal/cfb40/full_videos/OSU vs Oregon 01.01.25.mkv") # Working timestamps (from detected plays in the output JSON) # - Play #94 at 4104.5s works # - Play #148 at 6645.4s works WORKING_TIMESTAMPS = [4104.5, 6645.5] # Non-working timestamps (from ground truth) FAILING_TIMESTAMPS = [4136, 6684] def load_session_config(config_path: str) -> dict: """Load session config.""" with open(config_path, "r", encoding="utf-8") as f: return json.load(f) def main(): if not VIDEO_PATH.exists(): print(f"ERROR: Video not found at {VIDEO_PATH}") return # Load config video_basename = VIDEO_PATH.stem.replace(" ", "_").replace(".", "_") config_path = Path("output") / f"{video_basename}_config.json" config = load_session_config(str(config_path)) # Calculate absolute play clock coordinates playclock_coords = ( config["scorebug_x"] + config["playclock_x_offset"], config["scorebug_y"] + config["playclock_y_offset"], config["playclock_width"], config["playclock_height"], ) print(f"Playclock coords: {playclock_coords}") # Load digit templates template_dir = Path("output/debug/digit_templates") library = DigitTemplateLibrary() if not library.load(str(template_dir)): print(f"ERROR: Could not load digit templates from {template_dir}") return # Create clock reader reader = ReadPlayClock(library, region_width=config["playclock_width"], region_height=config["playclock_height"]) # Create output directory output_dir = Path("output/debug/clock_comparison") output_dir.mkdir(parents=True, exist_ok=True) print("\n" + "=" * 70) print("WORKING TIMESTAMPS (plays were detected here)") print("=" * 70) for ts in WORKING_TIMESTAMPS: frames = list(iter_frames_ffmpeg(str(VIDEO_PATH), start_time=ts, end_time=ts + 5, frame_interval=0.5)) print(f"\nTimestamp {ts}s:") for frame_time, frame in frames[:5]: pc_x, pc_y, pc_w, pc_h = playclock_coords playclock_region = frame[pc_y : pc_y + pc_h, pc_x : pc_x + pc_w].copy() preprocessed = preprocess_playclock_region(playclock_region, reader.scale_factor) result = reader.read_from_fixed_location(frame, playclock_coords, padding=10) status = f"value={result.value}, conf={result.confidence:.2f}" if result.detected else f"NOT DETECTED (conf={result.confidence:.2f})" print(f" t={frame_time:.1f}s: {status}") # Save comparison pc_scaled = cv2.resize(playclock_region, (pc_w * 10, pc_h * 10), interpolation=cv2.INTER_NEAREST) prep_bgr = cv2.cvtColor(preprocessed, cv2.COLOR_GRAY2BGR) prep_scaled = cv2.resize(prep_bgr, (pc_w * 10, pc_h * 10), interpolation=cv2.INTER_NEAREST) composite = np.vstack([pc_scaled, prep_scaled]) cv2.imwrite(str(output_dir / f"working_{int(ts)}_{int(frame_time)}.png"), composite) print("\n" + "=" * 70) print("FAILING TIMESTAMPS (plays were NOT detected here)") print("=" * 70) for ts in FAILING_TIMESTAMPS: frames = list(iter_frames_ffmpeg(str(VIDEO_PATH), start_time=ts, end_time=ts + 5, frame_interval=0.5)) print(f"\nTimestamp {ts}s:") for frame_time, frame in frames[:5]: pc_x, pc_y, pc_w, pc_h = playclock_coords playclock_region = frame[pc_y : pc_y + pc_h, pc_x : pc_x + pc_w].copy() preprocessed = preprocess_playclock_region(playclock_region, reader.scale_factor) result = reader.read_from_fixed_location(frame, playclock_coords, padding=10) status = f"value={result.value}, conf={result.confidence:.2f}" if result.detected else f"NOT DETECTED (conf={result.confidence:.2f})" print(f" t={frame_time:.1f}s: {status}") # Save comparison pc_scaled = cv2.resize(playclock_region, (pc_w * 10, pc_h * 10), interpolation=cv2.INTER_NEAREST) prep_bgr = cv2.cvtColor(preprocessed, cv2.COLOR_GRAY2BGR) prep_scaled = cv2.resize(prep_bgr, (pc_w * 10, pc_h * 10), interpolation=cv2.INTER_NEAREST) composite = np.vstack([pc_scaled, prep_scaled]) cv2.imwrite(str(output_dir / f"failing_{int(ts)}_{int(frame_time)}.png"), composite) print(f"\nSaved comparison images to: {output_dir}") if __name__ == "__main__": main()