| import os |
| import sys |
| import numpy as np |
| from typing import List |
|
|
| |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'ByteTrack')) |
|
|
| import yolox |
| from yolox.tracker.byte_tracker import BYTETracker, STrack |
| from onemetric.cv.utils.iou import box_iou_batch |
| from dataclasses import dataclass |
| from supervision import Detections |
|
|
| @dataclass(frozen=True) |
| class BYTETrackerArgs: |
| track_thresh: float = 0.25 |
| track_buffer: int = 30 |
| match_thresh: float = 0.8 |
| aspect_ratio_thresh: float = 3.0 |
| min_box_area: float = 1.0 |
| mot20: bool = False |
|
|
| |
| def detections2boxes(detections: Detections) -> np.ndarray: |
| return np.hstack(( |
| detections.xyxy, |
| detections.confidence[:, np.newaxis] |
| )) |
|
|
| |
| def tracks2boxes(tracks: List[STrack]) -> np.ndarray: |
| return np.array([ |
| track.tlbr |
| for track |
| in tracks |
| ], dtype=float) |
|
|
| |
| def match_detections_with_tracks( |
| detections: Detections, |
| tracks: List[STrack] |
| ) -> Detections: |
| if not np.any(detections.xyxy) or len(tracks) == 0: |
| return np.empty((0,)) |
|
|
| tracks_boxes = tracks2boxes(tracks=tracks) |
| iou = box_iou_batch(tracks_boxes, detections.xyxy) |
| track2detection = np.argmax(iou, axis=1) |
|
|
| tracker_ids = [None] * len(detections) |
|
|
| for tracker_index, detection_index in enumerate(track2detection): |
| if iou[tracker_index, detection_index] != 0: |
| tracker_ids[detection_index] = tracks[tracker_index].track_id |
|
|
| return tracker_ids |
|
|
| |
| import cv2 |
|
|
| class ViewTransformer: |
| """ |
| Transforms image coordinates to real-world coordinates using perspective transformation. |
| Used for calculating vehicle speeds in real-world units (meters, km/h). |
| """ |
| def __init__(self, source: np.ndarray, target: np.ndarray): |
| """ |
| Initialize the perspective transformer. |
| |
| Args: |
| source: 4 points in image coordinates forming a quadrilateral |
| target: 4 points in real-world coordinates (meters) |
| """ |
| source = source.astype(np.float32) |
| target = target.astype(np.float32) |
| self.m = cv2.getPerspectiveTransform(source, target) |
| |
| def transform_points(self, points: np.ndarray) -> np.ndarray: |
| """ |
| Transform points from image coordinates to real-world coordinates. |
| |
| Args: |
| points: Array of shape (N, 2) with [x, y] coordinates |
| |
| Returns: |
| Transformed points in real-world coordinates |
| """ |
| if len(points) == 0: |
| return np.array([]) |
| reshaped_points = points.reshape(-1, 1, 2).astype(np.float32) |
| transformed_points = cv2.perspectiveTransform(reshaped_points, self.m) |
| return transformed_points.reshape(-1, 2) |