This commit is contained in:
2026-03-23 11:13:30 -03:00
parent 8186bb5fe6
commit 71fd0510de
34 changed files with 1373 additions and 104 deletions

92
detect/profiles/soccer.py Normal file
View File

@@ -0,0 +1,92 @@
"""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=["logo", "text", "banner", "scoreboard"],
)
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 []