a
    yµÿfíA  ã                   @   s”   d dl 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é   )Úcheck_version)Úbbox_iouÚprobiou)Úxywhr2xyxyxyxyz1.10.0c                       sv   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d„Zdd„ Zeddd„ƒZedd„ ƒZ‡  ZS )ÚTaskAlignedAssignerao  
    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.
        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__© úQ/var/www/html/django/DPS/env/lib/python3.9/site-packages/ultralytics/utils/tal.pyr      s    
zTaskAlignedAssigner.__init__c                 C   s(  |j d | _|j d | _| jdkr‚|j}t |d | j¡ |¡t |¡ |¡t |¡ |¡t |d ¡ |¡t |d ¡ |¡fS |  	||||||¡\}}	}
|  
||
| j¡\}}}|  ||||¡\}}}|	|9 }	|	jddd}|
| jddd}|	| || j   d¡ d¡}|| }|||| ¡ |fS )a™  
        Compute the task-aligned assignment. Reference code is available at
        https://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.py.

        Args:
            pd_scores (Tensor): shape(bs, num_total_anchors, num_classes)
            pd_bboxes (Tensor): shape(bs, num_total_anchors, 4)
            anc_points (Tensor): shape(num_total_anchors, 2)
            gt_labels (Tensor): shape(bs, n_max_boxes, 1)
            gt_bboxes (Tensor): shape(bs, n_max_boxes, 4)
            mask_gt (Tensor): shape(bs, n_max_boxes, 1)

        Returns:
            target_labels (Tensor): shape(bs, num_total_anchors)
            target_bboxes (Tensor): shape(bs, num_total_anchors, 4)
            target_scores (Tensor): shape(bs, num_total_anchors, num_classes)
            fg_mask (Tensor): shape(bs, num_total_anchors)
            target_gt_idx (Tensor): shape(bs, num_total_anchors)
        r   r   ).r   éÿÿÿÿT)ÚdimÚkeepdiméþÿÿÿ)ÚshapeÚbsÚn_max_boxesÚdeviceÚtorchZ	full_liker   ÚtoZ
zeros_likeÚget_pos_maskÚselect_highest_overlapsÚget_targetsZamaxr   Ú	unsqueezeÚbool)r   Ú	pd_scoresÚ	pd_bboxesÚ
anc_pointsÚ	gt_labelsÚ	gt_bboxesÚmask_gtr!   Úmask_posÚalign_metricÚoverlapsÚtarget_gt_idxÚfg_maskÚtarget_labelsÚtarget_bboxesÚtarget_scoresZpos_align_metricsZpos_overlapsZnorm_align_metricr   r   r   Úforward&   s*    
ûÿ
zTaskAlignedAssigner.forwardc                 C   sZ   |   ||¡}|  |||||| ¡\}}	| j|| dd| j¡ ¡ d}
|
| | }|||	fS )z'Get in_gts mask, (b, max_num_obj, h*w).r   )Ú	topk_mask)Úselect_candidates_in_gtsÚget_box_metricsÚselect_topk_candidatesÚexpandr   r(   )r   r)   r*   r,   r-   r+   r.   Zmask_in_gtsr0   r1   Z	mask_topkr/   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 )
zICompute alignment metric given predicted and ground truth bounding boxes.r   ©Údtyper!   é   )r>   )Úendr   r   r   N)r   r(   r"   Úzerosr   r    r>   r!   ÚlongÚarangeÚviewr<   Úsqueezer'   Úiou_calculationÚpowr   r   )r   r)   r*   r,   r-   r.   Únar1   Zbbox_scoresÚindZpd_boxesZgt_boxesr0   r   r   r   r:   f   s    
$"z#TaskAlignedAssigner.get_box_metricsc                 C   s   t ||ddd d¡ d¡S )z.IoU calculation for horizontal bounding boxes.FT)ÚxywhZCIoUr   r   )r   rE   Úclamp_©r   r-   r*   r   r   r   rF   {   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 |¡ q–| |dkd¡ | |j¡S )	ah  
        Select the top-k candidates based on the given metrics.

        Args:
            metrics (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 (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:
            (Tensor): A tensor of shape (b, max_num_obj, h*w) containing the selected top-k candidates.
        r   )r   ÚlargestNT)r   r   r=   r   )r"   r   Úmaxr   Z	expand_asZmasked_fill_rA   r   Zint8r!   Z	ones_likeÚrangeZscatter_add_r#   r>   )	r   ÚmetricsrM   r8   Ztopk_metricsZ	topk_idxsZcount_tensorZonesÚkr   r   r   r;      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 (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 (Tensor): Ground truth bounding boxes of shape (b, max_num_obj, 4).
            target_gt_idx (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 (Tensor): A boolean tensor of shape (b, h*w) indicating the positive
                              (foreground) anchor points.

        Returns:
            (Tuple[Tensor, Tensor, Tensor]): A tuple containing the following tensors:
                - target_labels (Tensor): Shape (b, h*w), containing the target labels for
                                          positive anchor points.
                - target_bboxes (Tensor): Shape (b, h*w, 4), containing the target bounding boxes
                                          for positive anchor points.
                - target_scores (Tensor): Shape (b, h*w, num_classes), containing the target scores
                                          for positive anchor points, where num_classes is the number
                                          of object classes.
        )r@   r>   r!   ).Nr   r   r   r=   r?   N)r"   rC   r   Zint64r!   r    rB   ÚflattenrD   r   rK   rA   r   Úscatter_r'   ÚrepeatÚwhere)
r   r,   r-   r2   r3   Z	batch_indr4   r5   r6   Z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   r   r   é   r?   N©r   é   )r   rD   Úchunkr"   ÚcatZaminZgt_)
Ú
xy_centersr-   r   Z	n_anchorsr   Zn_boxesÚ_ÚltÚrbZbbox_deltasr   r   r   r9   Ò   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 )a   
        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).

        Note:
            b: batch size, h: height, w: width.
        r   r   r   r=   )ÚsumrN   r'   r<   Zargmaxr"   rA   r   r>   r!   rS   rU   Úfloat)r/   r1   r    r3   Zmask_multi_gtsZmax_overlaps_idxZis_max_overlapsr2   r   r   r   r%   ê   s    



z+TaskAlignedAssigner.select_highest_overlaps)r   r	   r
   r   r   )TN)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r"   Zno_gradr7   r$   r:   rF   r;   r&   Ústaticmethodr9   r%   Ú__classcell__r   r   r   r   r      s   

3
#0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+IoU calculation for rotated bounding boxes.r   r   )r   rE   rK   rL   r   r   r   rF     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 (Tensor): shape(h*w, 2)
            gt_bboxes (Tensor): shape(b, n_boxes, 5)

        Returns:
            (Tensor): shape(b, n_boxes, h*w)
        r   r   rW   r   r   )r   Úsplitr_   )r[   r-   ZcornersÚaÚbr\   ÚdÚabÚadZapZnorm_abZnorm_adZ	ap_dot_abZ	ap_dot_adr   r   r   r9     s    z3RotatedTaskAlignedAssigner.select_candidates_in_gtsN)ra   rb   rc   rd   rF   re   r9   r   r   r   r   rg     s   rg   ç      à?c              	   C   sî   g g  }}| dusJ ‚| d j | d j }}t|ƒD ]¤\}}| | j\}	}	}
}tj|||d| }tj|
||d| }trŠtj||ddn
t ||¡\}}| t 	||fd¡ 
dd¡¡ | tj|
| df|||d	¡ q4t |¡t |¡fS )
zGenerate anchors from features.Nr   )r@   r!   r>   Zij)Zindexingr   r?   r   r=   )r>   r!   Ú	enumerater   r"   rC   Ú
TORCH_1_10ZmeshgridÚappendÚstackrD   ÚfullrZ   )ZfeatsÚstridesZgrid_cell_offsetÚanchor_pointsZstride_tensorr>   r!   ÚiZstrider\   ÚhÚwÚsxZsyr   r   r   Úmake_anchors/  s    
$"rz   Tr   c           
      C   sX   |   d|¡\}}|| }|| }|rH|| d }|| }	t ||	f|¡S t ||f|¡S )z.Transform distance(ltrb) to box(xywh or xyxy).r?   )rY   r"   rZ   )
Zdistanceru   rJ   r   r]   r^   Úx1y1Úx2y2Zc_xyZwhr   r   r   Ú	dist2bbox>  s    r}   c                 C   s4   |  dd¡\}}t | | ||  fd¡ d|d ¡S )z#Transform bbox(xyxy) to dist(ltrb).r?   r   r   g{®Gáz„?)rY   r"   rZ   rK   )ru   ZbboxZreg_maxr{   r|   r   r   r   Ú	bbox2distJ  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, shape (bs, h*w, 4).
        pred_angle (torch.Tensor): Predicted angle, shape (bs, h*w, 1).
        anchor_points (torch.Tensor): Anchor points, shape (h*w, 2).
        dim (int, optional): Dimension along which to split. Defaults to -1.

    Returns:
        (torch.Tensor): Predicted rotated bounding boxes, shape (bs, h*w, 4).
    r?   rW   r   )rh   r"   ÚcosÚsinrZ   )Z	pred_distZ
pred_angleru   r   r]   r^   r   r€   ZxfZyfÚxÚyZxyr   r   r   Ú	dist2rboxP  s    "rƒ   )rn   )Tr   )r   )r"   Ztorch.nnÚnnZchecksr   rP   r   r   Úopsr   Ú__version__rp   ÚModuler   rg   rz   r}   r~   rƒ   r   r   r   r   Ú<module>   s     #

