Spaces:
Sleeping
Sleeping
| """ | |
| Region extraction utilities for play clock digit processing. | |
| This module provides utilities for extracting digit regions from preprocessed | |
| play clock images. The regions are used for both template building and matching. | |
| Play clock display layouts: | |
| - Single-digit (0-9): Digit is CENTER-aligned, tens position is blank | |
| - Double-digit (10-40): Tens on LEFT, ones on RIGHT | |
| These utilities are shared across: | |
| - readers/playclock.py (template matching) | |
| - setup/template_builder.py (template building) | |
| """ | |
| from typing import Any | |
| import cv2 | |
| import numpy as np | |
| from .color import normalize_to_grayscale | |
| def extract_left_region(preprocessed: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]: | |
| """ | |
| Extract left region for tens digit in double-digit displays. | |
| Args: | |
| preprocessed: Preprocessed play clock image (scaled up) | |
| Returns: | |
| Left region image for tens digit | |
| """ | |
| _, w = preprocessed.shape[:2] | |
| mid_x = w // 2 | |
| return preprocessed[:, : mid_x - 2] # Small gap in middle | |
| def extract_right_region(preprocessed: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]: | |
| """ | |
| Extract right region for ones digit in double-digit displays. | |
| Args: | |
| preprocessed: Preprocessed play clock image (scaled up) | |
| Returns: | |
| Right region image for ones digit | |
| """ | |
| _, w = preprocessed.shape[:2] | |
| mid_x = w // 2 | |
| return preprocessed[:, mid_x + 2 :] | |
| def extract_center_region(preprocessed: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]: | |
| """ | |
| Extract center region for ones digit in single-digit displays. | |
| The center region spans approximately 60% of the width, centered. | |
| Args: | |
| preprocessed: Preprocessed play clock image (scaled up) | |
| Returns: | |
| Center region image for centered single digit | |
| """ | |
| _, w = preprocessed.shape[:2] | |
| center_start = int(w * 0.20) | |
| center_end = int(w * 0.80) | |
| return preprocessed[:, center_start:center_end] | |
| def extract_far_left_region(preprocessed: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]: | |
| """ | |
| Extract far left region for blank detection in single-digit displays. | |
| This narrow region (0%-20% of width) doesn't overlap with a centered digit, | |
| so it should be truly empty when the clock shows a single digit. | |
| Args: | |
| preprocessed: Preprocessed play clock image (scaled up) | |
| Returns: | |
| Far left region image (should be mostly black for single digits) | |
| """ | |
| _, w = preprocessed.shape[:2] | |
| far_left_end = int(w * 0.20) | |
| return preprocessed[:, :far_left_end] | |
| def preprocess_playclock_region(region: np.ndarray[Any, Any], scale_factor: int = 4) -> np.ndarray[Any, Any]: | |
| """ | |
| Preprocess play clock region for template matching or building. | |
| Uses color normalization to handle both red and white digits uniformly, | |
| then scales and binarizes the image. | |
| Args: | |
| region: Play clock region (BGR format) | |
| scale_factor: Scale factor for upscaling (default: 4) | |
| Returns: | |
| Preprocessed binary image (white digits on black background) | |
| """ | |
| # Normalize color (red → white conversion happens here) | |
| gray = normalize_to_grayscale(region) | |
| # Scale up for better template quality/matching | |
| scaled = cv2.resize(gray, None, fx=scale_factor, fy=scale_factor, interpolation=cv2.INTER_LINEAR) | |
| # Use Otsu's thresholding | |
| _, binary = cv2.threshold(scaled, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) | |
| # Ensure white digits on black background (digits should be bright) | |
| mean_intensity = np.mean(np.asarray(binary)) | |
| if mean_intensity > 128: | |
| binary = cv2.bitwise_not(binary) | |
| return binary | |