import supervision as sv import football_analytics.config as config class FootballTracker: def __init__(self, detector, tracker_config=None): """ Initializes the tracker using the YOLO model from the detector. Args: detector (FootballDetector): An instance of FootballDetector tracker_config (str): Path or name of the tracker config (e.g. 'botsort.yaml') """ self.detector = detector self.tracker_config = tracker_config or config.TRACKER_CONFIG print(f"[Tracker] Initialized with config: {self.tracker_config}") def track(self, frame): """ Tracks players and the ball across frames. Args: frame (np.ndarray): Video frame (BGR format from OpenCV) Returns: sv.Detections: Supervision Detections object containing tracker_id. """ # Run YOLO in tracking mode results = self.detector.model.track( frame, persist=True, conf=self.detector.conf_threshold, iou=self.detector.iou_threshold, tracker=self.tracker_config, classes=self.detector.allowed_classes, verbose=False, device=self.detector.device )[0] # Convert to supervision detections (automatically parses tracker_id from boxes.id) detections = sv.Detections.from_ultralytics(results) # Sometimes class_id is empty or None, ensure arrays are initialized properly if detections.tracker_id is None and len(detections) > 0: # Fallback if tracker didn't assign IDs (e.g., first frame or tracking failed) # We assign a temporary negative ID or None import numpy as np detections.tracker_id = np.array([-1] * len(detections)) return detections