|
|
|
|
|
|
|
import numpy as np |
|
from typing import List |
|
|
|
from detectron2.config import CfgNode as CfgNode_ |
|
from detectron2.config import configurable |
|
from detectron2.structures import Instances |
|
from detectron2.structures.boxes import pairwise_iou |
|
from detectron2.tracking.utils import LARGE_COST_VALUE, create_prediction_pairs |
|
|
|
from .base_tracker import TRACKER_HEADS_REGISTRY |
|
from .hungarian_tracker import BaseHungarianTracker |
|
|
|
|
|
@TRACKER_HEADS_REGISTRY.register() |
|
class VanillaHungarianBBoxIOUTracker(BaseHungarianTracker): |
|
""" |
|
Hungarian algo based tracker using bbox iou as metric |
|
""" |
|
|
|
@configurable |
|
def __init__( |
|
self, |
|
*, |
|
video_height: int, |
|
video_width: int, |
|
max_num_instances: int = 200, |
|
max_lost_frame_count: int = 0, |
|
min_box_rel_dim: float = 0.02, |
|
min_instance_period: int = 1, |
|
track_iou_threshold: float = 0.5, |
|
**kwargs, |
|
): |
|
""" |
|
Args: |
|
video_height: height the video frame |
|
video_width: width of the video frame |
|
max_num_instances: maximum number of id allowed to be tracked |
|
max_lost_frame_count: maximum number of frame an id can lost tracking |
|
exceed this number, an id is considered as lost |
|
forever |
|
min_box_rel_dim: a percentage, smaller than this dimension, a bbox is |
|
removed from tracking |
|
min_instance_period: an instance will be shown after this number of period |
|
since its first showing up in the video |
|
track_iou_threshold: iou threshold, below this number a bbox pair is removed |
|
from tracking |
|
""" |
|
super().__init__( |
|
video_height=video_height, |
|
video_width=video_width, |
|
max_num_instances=max_num_instances, |
|
max_lost_frame_count=max_lost_frame_count, |
|
min_box_rel_dim=min_box_rel_dim, |
|
min_instance_period=min_instance_period, |
|
) |
|
self._track_iou_threshold = track_iou_threshold |
|
|
|
@classmethod |
|
def from_config(cls, cfg: CfgNode_): |
|
""" |
|
Old style initialization using CfgNode |
|
|
|
Args: |
|
cfg: D2 CfgNode, config file |
|
Return: |
|
dictionary storing arguments for __init__ method |
|
""" |
|
assert "VIDEO_HEIGHT" in cfg.TRACKER_HEADS |
|
assert "VIDEO_WIDTH" in cfg.TRACKER_HEADS |
|
video_height = cfg.TRACKER_HEADS.get("VIDEO_HEIGHT") |
|
video_width = cfg.TRACKER_HEADS.get("VIDEO_WIDTH") |
|
max_num_instances = cfg.TRACKER_HEADS.get("MAX_NUM_INSTANCES", 200) |
|
max_lost_frame_count = cfg.TRACKER_HEADS.get("MAX_LOST_FRAME_COUNT", 0) |
|
min_box_rel_dim = cfg.TRACKER_HEADS.get("MIN_BOX_REL_DIM", 0.02) |
|
min_instance_period = cfg.TRACKER_HEADS.get("MIN_INSTANCE_PERIOD", 1) |
|
track_iou_threshold = cfg.TRACKER_HEADS.get("TRACK_IOU_THRESHOLD", 0.5) |
|
return { |
|
"_target_": "detectron2.tracking.vanilla_hungarian_bbox_iou_tracker.VanillaHungarianBBoxIOUTracker", |
|
"video_height": video_height, |
|
"video_width": video_width, |
|
"max_num_instances": max_num_instances, |
|
"max_lost_frame_count": max_lost_frame_count, |
|
"min_box_rel_dim": min_box_rel_dim, |
|
"min_instance_period": min_instance_period, |
|
"track_iou_threshold": track_iou_threshold, |
|
} |
|
|
|
def build_cost_matrix(self, instances: Instances, prev_instances: Instances) -> np.ndarray: |
|
""" |
|
Build the cost matrix for assignment problem |
|
(https://en.wikipedia.org/wiki/Assignment_problem) |
|
|
|
Args: |
|
instances: D2 Instances, for current frame predictions |
|
prev_instances: D2 Instances, for previous frame predictions |
|
|
|
Return: |
|
the cost matrix in numpy array |
|
""" |
|
assert instances is not None and prev_instances is not None |
|
|
|
iou_all = pairwise_iou( |
|
boxes1=instances.pred_boxes, |
|
boxes2=self._prev_instances.pred_boxes, |
|
) |
|
bbox_pairs = create_prediction_pairs( |
|
instances, self._prev_instances, iou_all, threshold=self._track_iou_threshold |
|
) |
|
|
|
cost_matrix = np.full((len(instances), len(prev_instances)), LARGE_COST_VALUE) |
|
return self.assign_cost_matrix_values(cost_matrix, bbox_pairs) |
|
|
|
def assign_cost_matrix_values(self, cost_matrix: np.ndarray, bbox_pairs: List) -> np.ndarray: |
|
""" |
|
Based on IoU for each pair of bbox, assign the associated value in cost matrix |
|
|
|
Args: |
|
cost_matrix: np.ndarray, initialized 2D array with target dimensions |
|
bbox_pairs: list of bbox pair, in each pair, iou value is stored |
|
Return: |
|
np.ndarray, cost_matrix with assigned values |
|
""" |
|
for pair in bbox_pairs: |
|
|
|
cost_matrix[pair["idx"]][pair["prev_idx"]] = -1 |
|
return cost_matrix |
|
|