cfb40 / scripts /compare_clock_regions.py
andytaylor-smg's picture
in a good spot, I think
5d257ae
#!/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()