yolo8 / src /tracking /tracker.py
mayanktak15's picture
Upload folder using huggingface_hub
c94751c verified
Raw
History Blame Contribute Delete
1.77 kB
"""Tracking data models and interfaces."""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Sequence
import numpy as np
from src.detection.detector import BBox
@dataclass(slots=True)
class TrackedObject:
"""One tracked object at one frame."""
id: int
class_name: str
confidence: float
bbox: BBox
frame_index: int
@property
def centroid(self) -> tuple[float, float]:
x1, y1, x2, y2 = self.bbox
return ((x1 + x2) / 2.0, (y1 + y2) / 2.0)
def as_dict(self) -> dict[str, object]:
return {
"id": int(self.id),
"class": self.class_name,
"confidence": round(float(self.confidence), 4),
"bbox": [round(float(v), 2) for v in self.bbox],
}
@dataclass
class TrackHistory:
"""Persistent trajectory store keyed by track ID."""
points: dict[int, list[tuple[int, float, float]]] = field(default_factory=dict)
def update(self, tracks: Sequence[TrackedObject]) -> None:
for track in tracks:
x, y = track.centroid
self.points.setdefault(track.id, []).append((track.frame_index, x, y))
def get_recent_points(self, track_id: int, limit: int = 40) -> list[tuple[float, float]]:
return [(x, y) for _, x, y in self.points.get(track_id, [])[-limit:]]
def durations(self) -> dict[int, int]:
return {track_id: len(points) for track_id, points in self.points.items()}
class BaseTracker(ABC):
"""Contract for frame-level multi-object trackers."""
@abstractmethod
def update(self, frame: np.ndarray, frame_index: int) -> Sequence[TrackedObject]:
"""Return tracked objects for one BGR frame."""