o
    WñhEQ  ã                   @   s    d dl Z d dlmZ ddlmZ ddlmZ ddlmZm	Z	 ddl
mZ ee jdƒZG dd	„ d	ejƒZG d
d„ deƒZddd„Zddd„Zdd„ Zddd„ZdS )é    Né   )ÚLOGGER)Úcheck_version)Úbbox_iouÚprobiou)Úxywhr2xyxyxyxyz1.10.0c                       s~   e Zd ZdZd‡ fdd„	Ze ¡ d	d
„ ƒZdd„ Zdd„ Z	dd„ Z
dd„ Zddd„Zdd„ Zeddd„ƒZedd„ ƒZ‡  ZS ) ÚTaskAlignedAssignera  
    A task-aligned assigner for object detection.

    This class assigns ground-truth (gt) objects to anchors based on the task-aligned metric, which combines both
    classification and localization information.

    Attributes:
        topk (int): The number of top candidates to consider.
        num_classes (int): The number of object classes.
        bg_idx (int): Background class index.
        alpha (float): The alpha parameter for the classification component of the task-aligned metric.
        beta (float): The beta parameter for the localization component of the task-aligned metric.
        eps (float): A small value to prevent division by zero.
    é   éP   ç      ð?ç      @ç•Ö&è.>c                    s2   t ƒ  ¡  || _|| _|| _|| _|| _|| _dS )zJInitialize a TaskAlignedAssigner object with customizable hyperparameters.N)ÚsuperÚ__init__ÚtopkÚnum_classesÚbg_idxÚalphaÚbetaÚeps)Úselfr   r   r   r   r   ©Ú	__class__© úI/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/utils/tal.pyr      s   

zTaskAlignedAssigner.__init__c           	   
      sÖ   |j d | _|j d | _|j‰ | jdkr2t |d | j¡t |¡t |¡t |d ¡t |d ¡fS z|  ||||||¡W S  tj	j
yj   t d¡ dd„ ||||||fD ƒ}| j|Ž }t‡ fdd„|D ƒƒ Y S w )	a  
        Compute the task-aligned assignment.

        Args:
            pd_scores (torch.Tensor): Predicted classification scores with shape (bs, num_total_anchors, num_classes).
            pd_bboxes (torch.Tensor): Predicted bounding boxes with shape (bs, num_total_anchors, 4).
            anc_points (torch.Tensor): Anchor points with shape (num_total_anchors, 2).
            gt_labels (torch.Tensor): Ground truth labels with shape (bs, n_max_boxes, 1).
            gt_bboxes (torch.Tensor): Ground truth boxes with shape (bs, n_max_boxes, 4).
            mask_gt (torch.Tensor): Mask for valid ground truth boxes with shape (bs, n_max_boxes, 1).

        Returns:
            target_labels (torch.Tensor): Target labels with shape (bs, num_total_anchors).
            target_bboxes (torch.Tensor): Target bounding boxes with shape (bs, num_total_anchors, 4).
            target_scores (torch.Tensor): Target scores with shape (bs, num_total_anchors, num_classes).
            fg_mask (torch.Tensor): Foreground mask with shape (bs, num_total_anchors).
            target_gt_idx (torch.Tensor): Target ground truth indices with shape (bs, num_total_anchors).

        References:
            https://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.py
        r   r   ).r   z7CUDA OutOfMemoryError in TaskAlignedAssigner, using CPUc                 S   s   g | ]}|  ¡ ‘qS r   )Úcpu©Ú.0Útr   r   r   Ú
<listcomp>Q   s    z/TaskAlignedAssigner.forward.<locals>.<listcomp>c                 3   s    | ]}|  ˆ ¡V  qd S )N)Útor   ©Údevicer   r   Ú	<genexpr>S   s   € z.TaskAlignedAssigner.forward.<locals>.<genexpr>)ÚshapeÚbsÚn_max_boxesr"   ÚtorchÚ	full_liker   Ú
zeros_likeÚ_forwardÚcudaÚOutOfMemoryErrorr   ÚwarningÚtuple)	r   Ú	pd_scoresÚ	pd_bboxesÚ
anc_pointsÚ	gt_labelsÚ	gt_bboxesÚmask_gtÚcpu_tensorsÚresultr   r!   r   Úforward(   s$   
û

ûzTaskAlignedAssigner.forwardc                 C   s¦   |   ||||||¡\}}}	|  ||	| j¡\}
}}|  |||
|¡\}}}||9 }|jddd}|	| jddd}|| || j   d¡ d¡}|| }|||| ¡ |
fS )a–  
        Compute the task-aligned assignment.

        Args:
            pd_scores (torch.Tensor): Predicted classification scores with shape (bs, num_total_anchors, num_classes).
            pd_bboxes (torch.Tensor): Predicted bounding boxes with shape (bs, num_total_anchors, 4).
            anc_points (torch.Tensor): Anchor points with shape (num_total_anchors, 2).
            gt_labels (torch.Tensor): Ground truth labels with shape (bs, n_max_boxes, 1).
            gt_bboxes (torch.Tensor): Ground truth boxes with shape (bs, n_max_boxes, 4).
            mask_gt (torch.Tensor): Mask for valid ground truth boxes with shape (bs, n_max_boxes, 1).

        Returns:
            target_labels (torch.Tensor): Target labels with shape (bs, num_total_anchors).
            target_bboxes (torch.Tensor): Target bounding boxes with shape (bs, num_total_anchors, 4).
            target_scores (torch.Tensor): Target scores with shape (bs, num_total_anchors, num_classes).
            fg_mask (torch.Tensor): Foreground mask with shape (bs, num_total_anchors).
            target_gt_idx (torch.Tensor): Target ground truth indices with shape (bs, num_total_anchors).
        éÿÿÿÿT)ÚdimÚkeepdiméþÿÿÿ)Úget_pos_maskÚselect_highest_overlapsr&   Úget_targetsÚamaxr   Ú	unsqueezeÚbool)r   r/   r0   r1   r2   r3   r4   Úmask_posÚalign_metricÚoverlapsÚtarget_gt_idxÚfg_maskÚtarget_labelsÚtarget_bboxesÚtarget_scoresÚpos_align_metricsÚpos_overlapsÚnorm_align_metricr   r   r   r*   U   s   
ÿzTaskAlignedAssigner._forwardc                 C   sZ   |   ||¡}|  |||||| ¡\}}	| j|| dd| j¡ ¡ d}
|
| | }|||	fS )aÝ  
        Get positive mask for each ground truth box.

        Args:
            pd_scores (torch.Tensor): Predicted classification scores with shape (bs, num_total_anchors, num_classes).
            pd_bboxes (torch.Tensor): Predicted bounding boxes with shape (bs, num_total_anchors, 4).
            gt_labels (torch.Tensor): Ground truth labels with shape (bs, n_max_boxes, 1).
            gt_bboxes (torch.Tensor): Ground truth boxes with shape (bs, n_max_boxes, 4).
            anc_points (torch.Tensor): Anchor points with shape (num_total_anchors, 2).
            mask_gt (torch.Tensor): Mask for valid ground truth boxes with shape (bs, n_max_boxes, 1).

        Returns:
            mask_pos (torch.Tensor): Positive mask with shape (bs, max_num_obj, h*w).
            align_metric (torch.Tensor): Alignment metric with shape (bs, max_num_obj, h*w).
            overlaps (torch.Tensor): Overlaps between predicted and ground truth boxes with shape (bs, max_num_obj, h*w).
        r8   )Ú	topk_mask)Úselect_candidates_in_gtsÚget_box_metricsÚselect_topk_candidatesÚexpandr   rA   )r   r/   r0   r2   r3   r1   r4   Úmask_in_gtsrC   rD   Ú	mask_topkrB   r   r   r   r<   z   s
   
z TaskAlignedAssigner.get_pos_maskc                 C   s"  |j d }| ¡ }tj| j| j|g|j|jd}tj| j| j|g|j|jd}tjd| j| jgtjd}	tj	| jd 
dd¡ d| j¡|	d< | d¡|	d< ||	d d	d	…|	d f | ||< | d¡ d| jdd¡| }
| d¡ dd|d¡| }|  ||
¡||< | | j¡| | j¡ }||fS )
a8  
        Compute alignment metric given predicted and ground truth bounding boxes.

        Args:
            pd_scores (torch.Tensor): Predicted classification scores with shape (bs, num_total_anchors, num_classes).
            pd_bboxes (torch.Tensor): Predicted bounding boxes with shape (bs, num_total_anchors, 4).
            gt_labels (torch.Tensor): Ground truth labels with shape (bs, n_max_boxes, 1).
            gt_bboxes (torch.Tensor): Ground truth boxes with shape (bs, n_max_boxes, 4).
            mask_gt (torch.Tensor): Mask for valid ground truth boxes with shape (bs, n_max_boxes, h*w).

        Returns:
            align_metric (torch.Tensor): Alignment metric combining classification and localization.
            overlaps (torch.Tensor): IoU overlaps between predicted and ground truth boxes.
        r;   ©Údtyper"   é   )rU   )Úendr8   r   r   N)r$   rA   r'   Úzerosr%   r&   rU   r"   ÚlongÚarangeÚviewrQ   Úsqueezer@   Úiou_calculationÚpowr   r   )r   r/   r0   r2   r3   r4   ÚnarD   Úbbox_scoresÚindÚpd_boxesÚgt_boxesrC   r   r   r   rO   •   s   
$"z#TaskAlignedAssigner.get_box_metricsc                 C   s   t ||ddd d¡ d¡S )a  
        Calculate IoU for horizontal bounding boxes.

        Args:
            gt_bboxes (torch.Tensor): Ground truth boxes.
            pd_bboxes (torch.Tensor): Predicted boxes.

        Returns:
            (torch.Tensor): IoU values between each pair of boxes.
        FT)ÚxywhÚCIoUr8   r   )r   r\   Úclamp_©r   r3   r0   r   r   r   r]   ·   s   z#TaskAlignedAssigner.iou_calculationTNc           	   
   C   sà   t j|| jd|d\}}|du r|jdddd | jk |¡}| | d¡ t j|jt j|j	d}t j
|dd…dd…dd…f t j|j	d}t| jƒD ]}| d|dd…dd…||d …f |¡ qK| |dkd¡ | |j¡S )	az  
        Select the top-k candidates based on the given metrics.

        Args:
            metrics (torch.Tensor): A tensor of shape (b, max_num_obj, h*w), where b is the batch size,
                              max_num_obj is the maximum number of objects, and h*w represents the
                              total number of anchor points.
            largest (bool): If True, select the largest values; otherwise, select the smallest values.
            topk_mask (torch.Tensor): An optional boolean tensor of shape (b, max_num_obj, topk), where
                                topk is the number of top candidates to consider. If not provided,
                                the top-k values are automatically computed based on the given metrics.

        Returns:
            (torch.Tensor): A tensor of shape (b, max_num_obj, h*w) containing the selected top-k candidates.
        r8   )r9   ÚlargestNT)r:   r   rT   r   )r'   r   Úmaxr   Ú	expand_asÚmasked_fill_rX   r$   Úint8r"   Ú	ones_likeÚrangeÚscatter_add_r    rU   )	r   Úmetricsrh   rM   Útopk_metricsÚ	topk_idxsÚcount_tensorÚonesÚkr   r   r   rP   Ä   s   **z*TaskAlignedAssigner.select_topk_candidatesc           
      C   sÒ   t j| jt j|jdd }||| j  }| ¡  ¡ | }| d|j	d ¡| }| 
d¡ t j|j	d |j	d | jft j|jd}| d| d¡d¡ |dd…dd…df  dd| j¡}	t  |	dk|d¡}|||fS )	a  
        Compute target labels, target bounding boxes, and target scores for the positive anchor points.

        Args:
            gt_labels (torch.Tensor): Ground truth labels of shape (b, max_num_obj, 1), where b is the
                                batch size and max_num_obj is the maximum number of objects.
            gt_bboxes (torch.Tensor): Ground truth bounding boxes of shape (b, max_num_obj, 4).
            target_gt_idx (torch.Tensor): Indices of the assigned ground truth objects for positive
                                    anchor points, with shape (b, h*w), where h*w is the total
                                    number of anchor points.
            fg_mask (torch.Tensor): A boolean tensor of shape (b, h*w) indicating the positive
                              (foreground) anchor points.

        Returns:
            target_labels (torch.Tensor): Shape (b, h*w), containing the target labels for positive anchor points.
            target_bboxes (torch.Tensor): Shape (b, h*w, 4), containing the target bounding boxes for positive
                                          anchor points.
            target_scores (torch.Tensor): Shape (b, h*w, num_classes), containing the target scores for positive
                                          anchor points.
        )rW   rU   r"   ).Nr8   r   r   rT   rV   N)r'   rZ   r%   Úint64r"   r&   rY   Úflattenr[   r$   rf   rX   r   Úscatter_r@   ÚrepeatÚwhere)
r   r2   r3   rE   rF   Ú	batch_indrG   rH   rI   Úfg_scores_maskr   r   r   r>   æ   s   
ý"
zTaskAlignedAssigner.get_targetsc           
      C   sn   | j d }|j \}}}| ddd¡ dd¡\}}tj| d | || d  fdd |||d¡}	|	 d¡ |¡S )	aw  
        Select positive anchor centers within ground truth bounding boxes.

        Args:
            xy_centers (torch.Tensor): Anchor center coordinates, shape (h*w, 2).
            gt_bboxes (torch.Tensor): Ground truth bounding boxes, shape (b, n_boxes, 4).
            eps (float, optional): Small value for numerical stability. Defaults to 1e-9.

        Returns:
            (torch.Tensor): Boolean mask of positive anchors, shape (b, n_boxes, h*w).

        Note:
            b: batch size, n_boxes: number of ground truth boxes, h: height, w: width.
            Bounding box format: [x_min, y_min, x_max, y_max].
        r   r8   r   é   rV   N©r9   é   )r$   r[   Úchunkr'   ÚcatÚaminÚgt_)
Ú
xy_centersr3   r   Ú	n_anchorsr%   Ún_boxesÚ_ÚltÚrbÚbbox_deltasr   r   r   rN     s
   
.z,TaskAlignedAssigner.select_candidates_in_gtsc                 C   s’   |   d¡}| ¡ dkr?| d¡dk d|d¡}| d¡}tj| j| j| j	d}| 
d| d¡d¡ t ||| ¡ ¡ } |   d¡}|  d¡}||| fS )aa  
        Select anchor boxes with highest IoU when assigned to multiple ground truths.

        Args:
            mask_pos (torch.Tensor): Positive mask, shape (b, n_max_boxes, h*w).
            overlaps (torch.Tensor): IoU overlaps, shape (b, n_max_boxes, h*w).
            n_max_boxes (int): Maximum number of ground truth boxes.

        Returns:
            target_gt_idx (torch.Tensor): Indices of assigned ground truths, shape (b, h*w).
            fg_mask (torch.Tensor): Foreground mask, shape (b, h*w).
            mask_pos (torch.Tensor): Updated positive mask, shape (b, n_max_boxes, h*w).
        r;   r   r8   rT   )Úsumri   r@   rQ   Úargmaxr'   rX   r$   rU   r"   rx   rz   Úfloat)rB   rD   r&   rF   Úmask_multi_gtsÚmax_overlaps_idxÚis_max_overlapsrE   r   r   r   r=   *  s   




z+TaskAlignedAssigner.select_highest_overlaps)r	   r
   r   r   r   )TN)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r'   Úno_gradr7   r*   r<   rO   r]   rP   r>   ÚstaticmethodrN   r=   Ú__classcell__r   r   r   r   r      s    

,%"
"-r   c                   @   s$   e Zd ZdZdd„ Zedd„ ƒZdS )ÚRotatedTaskAlignedAssignerzSAssigns ground-truth objects to rotated bounding boxes using a task-aligned metric.c                 C   s   t ||ƒ d¡ d¡S )z)Calculate IoU for rotated bounding boxes.r8   r   )r   r\   rf   rg   r   r   r   r]   L  s   z*RotatedTaskAlignedAssigner.iou_calculationc                 C   s–   t |ƒ}|jddd\}}}}|| }|| }| | }	|| jdd}
|| jdd}|	| jdd}|	| jdd}|dk||
k@ |dk@ ||k@ S )a…  
        Select the positive anchor center in gt for rotated bounding boxes.

        Args:
            xy_centers (torch.Tensor): Anchor center coordinates with shape (h*w, 2).
            gt_bboxes (torch.Tensor): Ground truth bounding boxes with shape (b, n_boxes, 5).

        Returns:
            (torch.Tensor): Boolean mask of positive anchors with shape (b, n_boxes, h*w).
        r   r;   r~   r8   r   )r   Úsplitr‹   )r„   r3   ÚcornersÚaÚbr‡   ÚdÚabÚadÚapÚnorm_abÚnorm_adÚ	ap_dot_abÚ	ap_dot_adr   r   r   rN   P  s    z3RotatedTaskAlignedAssigner.select_candidates_in_gtsN)r‘   r’   r“   r”   r]   r–   rN   r   r   r   r   r˜   I  s
    r˜   ç      à?c              	   C   s  g g }}| dusJ ‚| d j | d j}}t|ƒD ]i\}}t| tƒr,| | jdd… nt| | d ƒt| | d ƒf\}	}
tj|
||d| }tj|	||d| }t	r\tj
||ddnt 
||¡\}}| t ||fd¡ dd¡¡ | tj|	|
 df|||d	¡ qt |¡t |¡fS )
zGenerate anchors from features.Nr   rV   r   )rW   r"   rU   Úij)Úindexingr8   rT   )rU   r"   Ú	enumerateÚ
isinstanceÚlistr$   Úintr'   rZ   Ú
TORCH_1_10ÚmeshgridÚappendÚstackr[   Úfullr   )ÚfeatsÚstridesÚgrid_cell_offsetÚanchor_pointsÚstride_tensorrU   r"   ÚiÚstrideÚhÚwÚsxÚsyr   r   r   Úmake_anchorsl  s   
@$"r¼   Tr8   c           
      C   sX   |   d|¡\}}|| }|| }|r$|| d }|| }	t ||	f|¡S t ||f|¡S )z.Transform distance(ltrb) to box(xywh or xyxy).rV   )r€   r'   r   )
Údistancer´   rd   r9   rˆ   r‰   Úx1y1Úx2y2Úc_xyÚwhr   r   r   Ú	dist2bbox{  s   rÂ   c                 C   s4   |  dd¡\}}t | | ||  fd¡ d|d ¡S )z#Transform bbox(xyxy) to dist(ltrb).rV   r8   r   g{®Gáz„?)r€   r'   r   rf   )r´   ÚbboxÚreg_maxr¾   r¿   r   r   r   Ú	bbox2dist‡  s   $rÅ   c                 C   s   | j d|d\}}t |¡t |¡}}|| d j d|d\}}	|| |	|  || |	|  }
}tj|
|g|d| }tj||| g|dS )a  
    Decode predicted rotated bounding box coordinates from anchor points and distribution.

    Args:
        pred_dist (torch.Tensor): Predicted rotated distance with shape (bs, h*w, 4).
        pred_angle (torch.Tensor): Predicted angle with shape (bs, h*w, 1).
        anchor_points (torch.Tensor): Anchor points with shape (h*w, 2).
        dim (int, optional): Dimension along which to split. Defaults to -1.

    Returns:
        (torch.Tensor): Predicted rotated bounding boxes with shape (bs, h*w, 4).
    rV   r~   r   )r™   r'   ÚcosÚsinr   )Ú	pred_distÚ
pred_angler´   r9   rˆ   r‰   rÆ   rÇ   ÚxfÚyfÚxÚyÚxyr   r   r   Ú	dist2rbox  s   "rÏ   )r¥   )Tr8   )r8   )r'   Útorch.nnÚnnÚ r   Úchecksr   rp   r   r   Úopsr   Ú__version__r¬   ÚModuler   r˜   r¼   rÂ   rÅ   rÏ   r   r   r   r   Ú<module>   s     =
#
