Source code for sportslabkit.metrics.tracking_preprocess

from __future__ import annotations

from itertools import chain
from typing import Any

import numpy as np
from scipy.spatial.distance import cdist

from sportslabkit import BBoxDataFrame
from sportslabkit.metrics.object_detection import convert_to_x1y1x2y2, iou_score


[docs]def to_mot_eval_format( gt_bbdf: BBoxDataFrame, pred_bbdf: BBoxDataFrame, ) -> dict[str, Any]: """Converts tracking and ground truth data to the format(dictionary) required by the MOT metrics. Args: gt_bbdf (BBoxDataFrame): Bbox Dataframe for ground truth tracking data. pred_bbdf (BBoxDataFrame): Bbox Dataframe for predicted tracking data. Returns: dict[str, Any]: Dictionary containing the data required by the MOT metrics Note: data is a dict containing all of the information that metrics need to perform evaluation. It contains the following fields: [num_timesteps, num_gt_ids, num_tracker_ids, num_gt_dets, num_tracker_dets] : integers. [gt_ids, tracker_ids]: list (for each timestep) of 1D NDArrays (for each det). [gt_dets, tracker_dets]: list (for each timestep) of lists of detection masks. [similarity_scores]: list (for each timestep) of 2D NDArrays. reference : https://github.com/JonathonLuiten/TrackEval/blob/ec237ec3ef654548fdc1fa1e100a45b31a6d4499/trackeval/datasets/mots_challenge.py """ if gt_bbdf.size == 0 and pred_bbdf.size == 0: data = {} data["tracker_ids"] = [] data["gt_ids"] = 0 data["tracker_dets"] = [] data["gt_dets"] = 0 data["similarity_scores"] = [] data["num_tracker_dets"] = 0 data["num_gt_dets"] = 0 data["num_tracker_ids"] = 0 data["num_gt_ids"] = 0 data["num_timesteps"] = 0 return data min_frame = min( gt_bbdf.first_valid_index() or pred_bbdf.first_valid_index(), pred_bbdf.first_valid_index() or gt_bbdf.first_valid_index(), ) max_frame = max( gt_bbdf.last_valid_index() or pred_bbdf.last_valid_index(), pred_bbdf.last_valid_index() or gt_bbdf.last_valid_index(), ) pred_bbdf = pred_bbdf.reindex(range(min_frame, max_frame + 1)) gt_bbdf = gt_bbdf.reindex(range(min_frame, max_frame + 1)) assert pred_bbdf.index.equals(gt_bbdf.index), f"Index mismatch: {pred_bbdf.index} != {gt_bbdf.index}" gt_ids, gt_dets = gt_bbdf.preprocess_for_mot_eval() pred_ids, pred_dets = pred_bbdf.preprocess_for_mot_eval() num_tracker_dets = sum(len(pred_dets[i]) for i in range(len(pred_dets))) num_gt_dets = sum(len(gt_dets[i]) for i in range(len(gt_dets))) unique_tracker_ids = np.unique(list(chain.from_iterable(pred_ids))) unique_gt_ids = np.unique(list(chain.from_iterable(gt_ids))) if num_tracker_dets == 0: data = {} data["tracker_ids"] = [] data["gt_ids"] = gt_ids data["tracker_dets"] = [] data["gt_dets"] = gt_dets data["similarity_scores"] = [] data["num_tracker_dets"] = 0 data["num_gt_dets"] = num_gt_dets data["num_tracker_ids"] = 0 data["num_gt_ids"] = len(unique_gt_ids) data["num_timesteps"] = len(gt_dets) return data if num_gt_dets == 0: data = {} data["tracker_ids"] = pred_ids data["gt_ids"] = [] data["tracker_dets"] = pred_dets data["gt_dets"] = [] data["similarity_scores"] = [] data["num_tracker_dets"] = num_tracker_dets data["num_gt_dets"] = 0 data["num_tracker_ids"] = len(unique_tracker_ids) data["num_gt_ids"] = 0 data["num_timesteps"] = 0 return data tracker_dets_xyxy = [[convert_to_x1y1x2y2(bbox) for bbox in frame_dets] for frame_dets in pred_dets] gt_dets_xyxy = [[convert_to_x1y1x2y2(bbox) for bbox in frame_dets] for frame_dets in gt_dets] sim_score_list = [] for i in range(len(gt_ids)): if len(gt_ids[i]) == 0 or len(pred_ids[i]) == 0: sim_score_list.append(np.array([[]])) else: sim_score = cdist(gt_dets_xyxy[i], tracker_dets_xyxy[i], iou_score) sim_score_list.append(sim_score) data = {} data["tracker_ids"] = pred_ids data["gt_ids"] = gt_ids data["tracker_dets"] = pred_dets data["gt_dets"] = gt_dets data["similarity_scores"] = sim_score_list data["num_tracker_dets"] = num_tracker_dets data["num_gt_dets"] = num_gt_dets data["num_tracker_ids"] = len(unique_tracker_ids) data["num_gt_ids"] = len(unique_gt_ids) data["num_timesteps"] = len(gt_dets) return data