class_docstr: Tracker for OC-SORT.
  
  Args:
      motion (dict): Configuration of motion. Defaults to None.
      obj_score_thrs (float): Detection score threshold for matching objects.
          Defaults to 0.3.
      init_track_thr (float): Detection score threshold for initializing a
          new tracklet. Defaults to 0.7.
      weight_iou_with_det_scores (bool): Whether using detection scores to
          weight IOU which is used for matching. Defaults to True.
      match_iou_thr (float): IOU distance threshold for matching between two
          frames. Defaults to 0.3.
      num_tentatives (int, optional): Number of continuous frames to confirm
          a track. Defaults to 3.
      vel_consist_weight (float): Weight of the velocity consistency term in
          association (OCM term in the paper).
      vel_delta_t (int): The difference of time step for calculating of the
          velocity direction of tracklets.
      init_cfg (dict or list[dict], optional): Initialization config dict.
          Defaults to None.
docstr: Apply Observation-Centric Momentum (OCM) to assign ids.
  
  OCM adds movement direction consistency into the association cost
  matrix. This term requires no additional assumption but from the
  same linear motion assumption as the canonical Kalman Filter in SORT.
  
  Args:
      ids (list[int]): Tracking ids.
      det_bboxes (Tensor): of shape (N, 4)
      det_labels (Tensor): of shape (N,)
      det_scores (Tensor): of shape (N,)
      weight_iou_with_det_scores (bool, optional): Whether using
          detection scores to weight IOU which is used for matching.
          Defaults to False.
      match_iou_thr (float, optional): Matching threshold.
          Defaults to 0.5.
  
  Returns:
      tuple(int): The assigning ids.
  
  OC-SORT uses velocity consistency besides IoU for association
docstr_tok: ["Apply","Observation-Centric","Momentum","(","OCM",")","to","assign","ids",".","OCM","adds","movement","direction","consistency","into","the","association","cost","matrix",".","This","term","requires","no","additional","assumption","but","from","the","same","linear","motion","assumption","as","the","canonical","Kalman","Filter","in","SORT",".","Args",":","ids","(","list","[","int","]",")",":","Tracking","ids",".","det_bboxes","(","Tensor",")",":","of","shape","(","N",",","4",")","det_labels","(","Tensor",")",":","of","shape","(","N",",",")","det_scores","(","Tensor",")",":","of","shape","(","N",",",")","weight_iou_with_det_scores","(","bool",",","optional",")",":","Whether","using","detection","scores","to","weight","IOU","which","is","used","for","matching",".","Defaults","to","False",".","match_iou_thr","(","float",",","optional",")",":","Matching","threshold",".","Defaults","to","0.5",".","Returns",":","tuple","(","int",")",":","The","assigning","ids",".","OC-SORT","uses","velocity","consistency","besides","IoU","for","association"]
code: def ocm_assign_ids(
      self,
      ids: List[int],
      det_bboxes: torch.Tensor,
      det_labels: torch.Tensor,
      det_scores: torch.Tensor,
      weight_iou_with_det_scores: Optional[bool] = False,
      match_iou_thr: Optional[float] = 0.5,
  ):
      """Apply Observation-Centric Momentum (OCM) to assign ids.
  
      OCM adds movement direction consistency into the association cost
      matrix. This term requires no additional assumption but from the
      same linear motion assumption as the canonical Kalman Filter in SORT.
  
      Args:
          ids (list[int]): Tracking ids.
          det_bboxes (Tensor): of shape (N, 4)
          det_labels (Tensor): of shape (N,)
          det_scores (Tensor): of shape (N,)
          weight_iou_with_det_scores (bool, optional): Whether using
              detection scores to weight IOU which is used for matching.
              Defaults to False.
          match_iou_thr (float, optional): Matching threshold.
              Defaults to 0.5.
  
      Returns:
          tuple(int): The assigning ids.
  
      OC-SORT uses velocity consistency besides IoU for association
      """
      # get track_bboxes
      track_bboxes = np.zeros((0, 4))
      for id in ids:
          track_bboxes = np.concatenate(
              (track_bboxes, self.tracks[id].mean[:4][None]), axis=0
          )
      track_bboxes = torch.from_numpy(track_bboxes).to(det_bboxes)
      track_bboxes = bbox_cxcyah_to_xyxy(track_bboxes)
  
      # compute distance
      ious = bbox_overlaps(track_bboxes, det_bboxes)
      if weight_iou_with_det_scores:
          ious *= det_scores
  
      # support multi-class association
      track_labels = torch.tensor(
          [self.tracks[id]["labels"][-1] for id in ids]
      ).to(det_bboxes.device)
      cate_match = det_labels[None, :] == track_labels[:, None]
      # to avoid det and track of different categories are matched
      cate_cost = (1 - cate_match.int()) * 1e6
  
      dists = (1 - ious + cate_cost).cpu().numpy()
  
      if len(ids) > 0 and len(det_bboxes) > 0:
          track_velocities = torch.stack(
              [self.tracks[id].velocity for id in ids]
          ).to(det_bboxes.device)
          k_step_observations = torch.stack(
              [self.k_step_observation(self.tracks[id]) for id in ids]
          ).to(det_bboxes.device)
          # valid1: if the track has previous observations to estimate speed
          # valid2: if the associated observation k steps ago is a detection
          valid1 = track_velocities.sum(dim=1) != -2
          valid2 = k_step_observations.sum(dim=1) != -4
          valid = valid1 & valid2
  
          vel_to_match = self.vel_direction_batch(
              k_step_observations, det_bboxes
          )
          track_velocities = track_velocities[:, None, :].repeat(
              1, det_bboxes.shape[0], 1
          )
  
          angle_cos = (vel_to_match * track_velocities).sum(dim=-1)
          angle_cos = torch.clamp(angle_cos, min=-1, max=1)
          angle = torch.acos(angle_cos)  # [0, pi]
          norm_angle = (angle - np.pi / 2.0) / np.pi  # [-0.5, 0.5]
          valid_matrix = (
              valid[:, None].int().repeat(1, det_bboxes.shape[0])
          )
          # set non-valid entries 0
          valid_norm_angle = norm_angle * valid_matrix
  
          dists += (
              valid_norm_angle.cpu().numpy() * self.vel_consist_weight
          )
  
      # bipartite match
      if dists.size > 0:
          cost, row, col = lap.lapjv(
              dists, extend_cost=True, cost_limit=1 - match_iou_thr
          )
      else:
          row = np.zeros(len(ids)).astype(np.int32) - 1
          col = np.zeros(len(det_bboxes)).astype(np.int32) - 1
      return row, col
  
imports: from typing import List, Optional, Tuple
  import numpy
  import torch
  from addict import Dict
  from mmengine.structures import InstanceData
  from mmdet.registry import MODELS
  from mmdet.structures import DetDataSample
  from mmdet.structures.bbox import bbox_cxcyah_to_xyxy, bbox_overlaps, bbox_xyxy_to_cxcyah
  from .sort_tracker import SORTTracker
label_desc: Use image node_id 8 for calling the OCSORTTracker obj's underlying member method code with example usage: obj.ocm_assign_ids(ids, det_bboxes, det_labels, det_scores, weight_iou_with_det_scores, match_iou_thr) and returns: row,  col