"""Soccer broadcast profile — pitch hoardings, kits, scoreboards.""" from __future__ import annotations from detect.models import BrandDetection, BrandStats, DetectionReport, PipelineStats from .base import ( BrandDictionary, CropContext, DetectionConfig, FrameExtractionConfig, OCRConfig, ResolverConfig, SceneFilterConfig, ) class SoccerBroadcastProfile: name = "soccer_broadcast" def frame_extraction_config(self) -> FrameExtractionConfig: return FrameExtractionConfig(fps=2.0, max_frames=500) def scene_filter_config(self) -> SceneFilterConfig: return SceneFilterConfig(hamming_threshold=8, enabled=True) def detection_config(self) -> DetectionConfig: return DetectionConfig( model_name="yolov8n.pt", confidence_threshold=0.3, target_classes=[], # empty = accept all COCO classes (until custom model) ) def ocr_config(self) -> OCRConfig: return OCRConfig(languages=["en", "es"], min_confidence=0.5) def brand_dictionary(self) -> BrandDictionary: return BrandDictionary(brands={ "Nike": ["nike", "NIKE", "swoosh"], "Adidas": ["adidas", "ADIDAS", "adi"], "Puma": ["puma", "PUMA"], "Emirates": ["emirates", "fly emirates", "EMIRATES"], "Coca-Cola": ["coca-cola", "coca cola", "coke", "COCA-COLA"], "Pepsi": ["pepsi", "PEPSI"], "Mastercard": ["mastercard", "MASTERCARD"], "Heineken": ["heineken", "HEINEKEN"], "Santander": ["santander", "SANTANDER"], "Gazprom": ["gazprom", "GAZPROM"], "Qatar Airways": ["qatar airways", "QATAR AIRWAYS"], "Lay's": ["lays", "lay's", "LAYS", "LAY'S"], }) def resolver_config(self) -> ResolverConfig: return ResolverConfig(fuzzy_threshold=75) def vlm_prompt(self, crop_context: CropContext) -> str: hint = f" Position: {crop_context.position_hint}." if crop_context.position_hint else "" text = f" Nearby text: '{crop_context.surrounding_text}'." if crop_context.surrounding_text else "" return ( f"Identify the brand or sponsor visible in this cropped region " f"from a soccer broadcast.{hint}{text} " f"Respond with: brand, confidence (0-1), reasoning." ) def aggregate(self, detections: list[BrandDetection]) -> DetectionReport: brands: dict[str, BrandStats] = {} for d in detections: if d.brand not in brands: brands[d.brand] = BrandStats() s = brands[d.brand] s.total_appearances += 1 s.total_screen_time += d.duration s.avg_confidence = ( (s.avg_confidence * (s.total_appearances - 1) + d.confidence) / s.total_appearances ) if s.first_seen == 0.0 or d.timestamp < s.first_seen: s.first_seen = d.timestamp if d.timestamp > s.last_seen: s.last_seen = d.timestamp return DetectionReport( video_source="", content_type=self.name, duration_seconds=0.0, brands=brands, timeline=sorted(detections, key=lambda d: d.timestamp), pipeline_stats=PipelineStats(), ) def auxiliary_detections(self, source: str) -> list[BrandDetection]: return []