o
    Wh                  
   @   s   d dl Zd dlZd dlmZ d dlmZmZ zd dlZej	s J W n e
eefy;   d dlmZ ed d dlZY nw ddejded	ed
efddZdeded
ejfddZddededed
ejfddZdejded
ejfddZdS )    N)cdist)batch_probioubbox_ioa)check_requirementszlap>=0.5.12Tcost_matrixthreshuse_lapreturnc                    sZ   j dkrtjdtdtt jd tt jd fS |rFtj dd\}dd t	D }t
dk d }t
dk d }nbtj \t fd	dttD }t|dkr|tt jd }tt jd }n,ttt jd t|d
d
df  }ttt jd t|d
d
df  }|||fS )a  
    Perform linear assignment using either the scipy or lap.lapjv method.

    Args:
        cost_matrix (np.ndarray): The matrix containing cost values for assignments, with shape (N, M).
        thresh (float): Threshold for considering an assignment valid.
        use_lap (bool): Use lap.lapjv for the assignment. If False, scipy.optimize.linear_sum_assignment is used.

    Returns:
        matched_indices (np.ndarray): Array of matched indices of shape (K, 2), where K is the number of matches.
        unmatched_a (np.ndarray): Array of unmatched indices from the first set, with shape (L,).
        unmatched_b (np.ndarray): Array of unmatched indices from the second set, with shape (M,).

    Examples:
        >>> cost_matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
        >>> thresh = 5.0
        >>> matched_indices, unmatched_a, unmatched_b = linear_assignment(cost_matrix, thresh, use_lap=True)
    r   )r      dtype   T)extend_cost
cost_limitc                 S   s    g | ]\}}|d kr||gqS )r    ).0ixmxr   r   W/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/trackers/utils/matching.py
<listcomp>.   s     z%linear_assignment.<locals>.<listcomp>c                    s4   g | ]} | | f kr| | gqS r   r   )r   ir   r   xyr   r   r   5   s   4 N)sizenpemptyinttuplerangeshapelaplapjv	enumeratewherescipyoptimizelinear_sum_assignmentasarraylenlistarange	frozenset)r   r   r   _matchesunmatched_aunmatched_br   r   r   linear_assignment   s   
0&,,
r1   atracksbtracksc                 C   s   | r
t | d tjs|rt |d tjr| }|}ndd | D }dd |D }tjt|t|ftjd}t|rwt|rwt|d dkrdt|d dkrdttj|tjdtj|tjd }d	| S t	tj|tjdtj|tjddd}d	| S )
a  
    Compute cost based on Intersection over Union (IoU) between tracks.

    Args:
        atracks (List[STrack] | List[np.ndarray]): List of tracks 'a' or bounding boxes.
        btracks (List[STrack] | List[np.ndarray]): List of tracks 'b' or bounding boxes.

    Returns:
        (np.ndarray): Cost matrix computed based on IoU with shape (len(atracks), len(btracks)).

    Examples:
        Compute IoU distance between two sets of tracks
        >>> atracks = [np.array([0, 0, 10, 10]), np.array([20, 20, 30, 30])]
        >>> btracks = [np.array([5, 5, 15, 15]), np.array([25, 25, 35, 35])]
        >>> cost_matrix = iou_distance(atracks, btracks)
    r   c                 S   "   g | ]}|j d ur|jn|jqS Nanglexywhaxyxyr   trackr   r   r   r   U      " z iou_distance.<locals>.<listcomp>c                 S   r4   r5   r6   r:   r   r   r   r   V   r<   r      T)iour   )

isinstancer   ndarrayzerosr)   float32r   ascontiguousarraynumpyr   )r2   r3   atlbrsbtlbrsiousr   r   r   iou_distance@   s*   ( 
rH   cosinetracks
detectionsmetricc                 C   sv   t jt| t|ft jd}|jdkr|S t jdd |D t jd}t jdd | D t jd}t dt|||}|S )a  
    Compute distance between tracks and detections based on embeddings.

    Args:
        tracks (List[STrack]): List of tracks, where each track contains embedding features.
        detections (List[BaseTrack]): List of detections, where each detection contains embedding features.
        metric (str): Metric for distance computation. Supported metrics include 'cosine', 'euclidean', etc.

    Returns:
        (np.ndarray): Cost matrix computed based on embeddings with shape (N, M), where N is the number of tracks
            and M is the number of detections.

    Examples:
        Compute the embedding distance between tracks and detections using cosine metric
        >>> tracks = [STrack(...), STrack(...)]  # List of track objects with embedding features
        >>> detections = [BaseTrack(...), BaseTrack(...)]  # List of detection objects with embedding features
        >>> cost_matrix = embedding_distance(tracks, detections, metric="cosine")
    r   r   c                 S      g | ]}|j qS r   )	curr_featr:   r   r   r   r   ~       z&embedding_distance.<locals>.<listcomp>c                 S   rM   r   )smooth_featr:   r   r   r   r      rO   g        )r   rA   r)   rB   r   r(   maximumr   )rJ   rK   rL   r   det_featurestrack_featuresr   r   r   embedding_distanceh   s   
rT   c                 C   sX   | j dkr| S d|  }tdd |D }tj|ddj| jd dd}|| }d| S )a  
    Fuse cost matrix with detection scores to produce a single similarity matrix.

    Args:
        cost_matrix (np.ndarray): The matrix containing cost values for assignments, with shape (N, M).
        detections (List[BaseTrack]): List of detections, each containing a score attribute.

    Returns:
        (np.ndarray): Fused similarity matrix with shape (N, M).

    Examples:
        Fuse a cost matrix with detection scores
        >>> cost_matrix = np.random.rand(5, 10)  # 5 tracks and 10 detections
        >>> detections = [BaseTrack(score=np.random.rand()) for _ in range(10)]
        >>> fused_matrix = fuse_score(cost_matrix, detections)
    r   r   c                 S   rM   r   )score)r   detr   r   r   r      rO   zfuse_score.<locals>.<listcomp>)axis)r   r   arrayexpand_dimsrepeatr    )r   rK   iou_sim
det_scoresfuse_simr   r   r   
fuse_score   s   
r^   )T)rI   )rD   r   r%   scipy.spatial.distancer   ultralytics.utils.metricsr   r   r!   __version__ImportErrorAssertionErrorAttributeErrorultralytics.utils.checksr   r@   floatboolr   r1   r*   rH   strrT   r^   r   r   r   r   <module>   s    ,(