
    |hQ                         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	ej                        Z G d
 de      ZddZddZd ZddZy)    N   )LOGGER)check_version)bbox_iouprobiou)xywhr2xyxyxyxyz1.10.0c                        e Zd ZdZddededededef
 fdZ ej                         d        Z	d	 Z
d
 Zd Zd ZddZd Zedd       Zed        Z x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.
    topknum_classesalphabetaepsc                 h    t         |           || _        || _        || _        || _        || _        y)a4  
        Initialize a TaskAlignedAssigner object with customizable hyperparameters.

        Args:
            topk (int, optional): The number of top candidates to consider.
            num_classes (int, optional): The number of object classes.
            alpha (float, optional): The alpha parameter for the classification component of the task-aligned metric.
            beta (float, optional): The beta parameter for the localization component of the task-aligned metric.
            eps (float, optional): A small value to prevent division by zero.
        N)super__init__r   r   r   r   r   )selfr   r   r   r   r   	__class__s         T/var/www/html/test/engine/venv/lib/python3.12/site-packages/ultralytics/utils/tal.pyr   zTaskAlignedAssigner.__init__   s4     		&
	    c                   
 |j                   d   | _        |j                   d   | _        |j                  
| j                  dk(  rzt	        j
                  |d   | j                        t	        j                  |      t	        j                  |      t	        j                  |d         t	        j                  |d         fS 	 | j                  ||||||      S # t        j                  j                  $ rd t        j                  d       ||||||fD cg c]  }|j                          nc c}w }} | j                  | }	t        
fd|	D              cY S w xY 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              3   @   K   | ]  }|j                          y wN)to).0tdevices     r   	<genexpr>z.TaskAlignedAssigner.forward.<locals>.<genexpr>Z   s     6!f6s   )shapebsn_max_boxesr   torch	full_liker   
zeros_like_forwardcudaOutOfMemoryErrorr   warningcputuple)r   	pd_scores	pd_bboxes
anc_points	gt_labels	gt_bboxesmask_gtr   cpu_tensorsresultr   s             @r   forwardzTaskAlignedAssigner.forward/   s5   . //!$$??1-!!q 	& 143C3CD  +  +  6!23  6!23 	7==Iz9iY`aazz** 	7NNTU-6	:yZcel,mnq1557nnKn"T]]K0F6v666	7s    C <ED*)+EEc                    | j                  ||||||      \  }}}	| j                  ||	| j                        \  }
}}| j                  |||
|      \  }}}||z  }|j	                  dd      }|	|z  j	                  dd      }||z  || j
                  z   z  j	                  d      j                  d      }||z  }||||j                         |
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+   r,   r-   r.   r/   r0   mask_posalign_metricoverlapstarget_gt_idxfg_masktarget_labelstarget_bboxestarget_scorespos_align_metricspos_overlapsnorm_align_metrics                     r   r%   zTaskAlignedAssigner._forward\   s   & ,0+<+<y)Y
G,
(, ,0+G+GRZ\`\l\l+m(w 7;6F6FyR[]jls6t3}m 	 (--"d-C 8+11b$1G)L8<MPTPXPX<XY__`bcmmnpq%(99m]GLLNMYYr   c                     | j                  ||      }| j                  ||||||z        \  }}	| j                  ||j                  dd| j                        j                               }
|
|z  |z  }|||	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).
        r5   )	topk_mask)select_candidates_in_gtsget_box_metricsselect_topk_candidatesexpandr   r>   )r   r+   r,   r.   r/   r-   r0   mask_in_gtsr@   rA   	mask_topkr?   s               r   r9   z TaskAlignedAssigner.get_pos_mask   s    " 33J	J!%!5!5iIW`bmpwbw!xh//WY[]_c_h_hHiHnHnHp/q	{*W4x//r   c                    |j                   d   }|j                         }t        j                  | j                  | j
                  |g|j                  |j                        }t        j                  | j                  | j
                  |g|j                  |j                        }t        j                  d| j                  | j
                  gt        j                        }	t        j                  | j                        j                  dd      j                  d| j
                        |	d<   |j                  d      |	d<   ||	d   d	d	|	d   f   |   ||<   |j                  d      j                  d| j
                  dd      |   }
|j                  d      j                  dd|d      |   }| j                  ||
      ||<   |j                  | j                         |j                  | j"                        z  }||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.
        r8   dtyper      )rT   )endr5   r   r   N)r   r>   r"   zerosr    r!   rT   r   longarangeviewrO   squeezer=   iou_calculationpowr   r   )r   r+   r,   r.   r/   r0   narA   bbox_scoresindpd_boxesgt_boxesr@   s                r   rM   z#TaskAlignedAssigner.get_box_metrics   s    __R ,,.;;)9)92>ioo^g^n^nokk477D,<,<b"Aajaqaqrkk1dggt'7'78

K$''*//A6==b$BRBRSA""2&A(QCF):;GDG &&q)00T5E5Er2NwW&&q)00RR@I 008D"tzz2X\\$))5LLX%%r   c                 \    t        ||dd      j                  d      j                  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CIoUr5   r   )r   r[   clamp_r   r/   r,   s      r   r\   z#TaskAlignedAssigner.iou_calculation   s,     	95tDLLRPWWXYZZr   c           
         t        j                  || j                  dd      \  }}|2|j                  dd      d   | j                  kD  j	                  |      }|j                  | d       t        j                  |j                  t         j                  |j                        }t        j                  |ddddddf   t         j                  |j                        }t        | j                        D ]$  }|j                  d|dddd||dz   f   |       & |j                  |dkD  d       |j                  |j                        S )	a  
        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.
            topk_mask (torch.Tensor, optional): 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.
        r5   T)r6   largestN)r7   r   rS   r   )r"   r   maxr   	expand_asmasked_fill_rW   r   int8r   	ones_likerangescatter_add_r   rT   )r   metricsrK   topk_metrics	topk_idxscount_tensoronesks           r   rN   z*TaskAlignedAssigner.select_topk_candidates   s    #(**WdiiRQU"Vi%))"d);A>ITTU^_I	z1- {{7==

9K[K[\yArr2%**YM]M]^tyy! 	LA%%b)Aq!a!e)O*DdK	L 	!!,"2A6w}}--r   c                    t        j                  | j                  t         j                  |j                        d   }||| j
                  z  z   }|j                         j                         |   }|j                  d|j                  d         |   }|j                  d       t        j                  |j                  d   |j                  d   | j                  ft         j                  |j                        }|j                  d|j                  d      d       |dddddf   j                  dd| j                        }	t        j                   |	dkD  |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): Target labels for positive anchor points with shape (b, h*w).
            target_bboxes (torch.Tensor): Target bounding boxes for positive anchor points with shape (b, h*w, 4).
            target_scores (torch.Tensor): Target scores for positive anchor points with shape (b, h*w, num_classes).
        )rV   rT   r   ).Nr5   r   r   rS   rU   N)r"   rY   r    int64r   r!   rX   flattenrZ   r   rf   rW   r   scatter_r=   repeatwhere)
r   r.   r/   rB   rC   	batch_indrD   rE   rF   fg_scores_masks
             r   r;   zTaskAlignedAssigner.get_targets   s7   ( LLTWWEKK	HXHXYZcd	%	D4D4D(DD!(002=A "r9??2+>?N 	Q   #]%8%8%;T=M=MN++ ''

 	q-"9"9""=qA At,33Aq$:J:JKNQ$6qIm]::r   c                 :   | j                   d   }|j                   \  }}}|j                  ddd      j                  dd      \  }}t        j                  | d   |z
  || d   z
  fd      j                  |||d      }	|	j                  d      j                  |      S )	ae  
        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.

        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   r5   r      rU   Nr6      )r   rZ   chunkr"   catamingt_)

xy_centersr/   r   	n_anchorsr    n_boxes_ltrbbbox_deltass
             r   rL   z,TaskAlignedAssigner.select_candidates_in_gts  s    " $$Q'	"GQAq)//15BiiD!1B!6Z=M8M NTUV[[\^`girtvw"&&s++r   c                    | j                  d      }|j                         dkD  r|j                  d      dkD  j                  d|d      }|j	                  d      }t        j                  | j                  | j                  | j                        }|j                  d|j                  d      d       t        j                  |||       j                         } | j                  d      }| j	                  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).
        r8   r   r5   rS   )sumrj   r=   rO   argmaxr"   rW   r   rT   r   rz   r|   float)r?   rA   r!   rC   mask_multi_gtsmax_overlaps_idxis_max_overlapsrB   s           r   r:   z+TaskAlignedAssigner.select_highest_overlaps-  s      ,,r";;=1%//2Q6>>r;PRSN'q1#kk(..W_WfWfgO$$Q(8(B(B1(EqI{{>?HMSSUHll2&G +gx//r   )   P   g      ?g      @&.>r   )r   )__name__
__module____qualname____doc__intr   r   r"   no_gradr3   r%   r9   rM   r\   rN   r;   staticmethodrL   r:   __classcell__)r   s   @r   r
   r
      s    S C U X] jo $ U]]_*7 *7X#ZJ06 &D[.@);V , ,, 0 0r   r
   c                   &    e Zd ZdZd Zed        Zy)RotatedTaskAlignedAssignerzSAssigns ground-truth objects to rotated bounding boxes using a task-aligned metric.c                 V    t        ||      j                  d      j                  d      S )z)Calculate IoU for rotated bounding boxes.r5   r   )r   r[   rf   rg   s      r   r\   z*RotatedTaskAlignedAssigner.iou_calculationO  s%    y),44R8??BBr   c                 <   t        |      }|j                  dd      \  }}}}||z
  }||z
  }| |z
  }	||z  j                  d      }
||z  j                  d      }|	|z  j                  d      }|	|z  j                  d      }|dk\  ||
k  z  |dk\  z  ||k  z  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   r8   r   r5   r   )r   splitr   )r   r/   cornersabr   dabadapnorm_abnorm_ad	ap_dot_ab	ap_dot_ads                 r   rL   z3RotatedTaskAlignedAssigner.select_candidates_in_gtsS  s     !+]]1"]-
1aUU !^7--B-'7--B-'"WMMbM)	"WMMbM)	Q9#78INKy\cOcddr   N)r   r   r   r   r\   r   rL    r   r   r   r   L  s!    ]C e er   r   c           	         g g }}| J | d   j                   | d   j                  }}t        |      D ]  \  }}t        | t              r| |   j
                  dd n!t        | |   d         t        | |   d         f\  }	}
t        j                  |
||      |z   }t        j                  |	||      |z   }t        rt        j                  ||d      nt        j                  ||      \  }}|j                  t        j                  ||fd      j                  dd             |j                  t        j                  |	|
z  df|||	             ! t        j                  |      t        j                  |      fS )
zGenerate anchors from features.Nr   rU   r   )rV   r   rT   ij)indexingr5   rS   )rT   r   	enumerate
isinstancelistr   r   r"   rY   
TORCH_1_10meshgridappendstackrZ   fullr   )featsstridesgrid_cell_offsetanchor_pointsstride_tensorrT   r   istridehwsxsys                r   make_anchorsr   o  sY   #%r=M!HNNE!HOO6Ew' Y	6%/t%<uQx~~ab!3uQxPQ{CSUXY^_`YabcYdUeBf1\\ae<?OO\\ae<?OO:DB6%..Y[]_J`BU[["b26;;BBCUZZQ
F%PVWXY 99]#UYY}%===r   c                     | j                  d|      \  }}||z
  }||z   }|r%||z   dz  }||z
  }	t        j                  ||	f|      S t        j                  ||f|      S )z.Transform distance(ltrb) to box(xywh or xyxy).rU   )r   r"   r   )
distancer   rd   r6   r   r   x1y1x2y2c_xywhs
             r   	dist2bboxr   ~  sn    ^^As#FB2D2Dtq D[yy$S))99dD\3''r   c                     |j                  dd      \  }}t        j                  | |z
  || z
  fd      j                  d|dz
        S )z#Transform bbox(xyxy) to dist(ltrb).rU   r5   r   g{Gz?)r   r"   r   rf   )r   bboxreg_maxr   r   s        r   	bbox2distr     sJ    Ar"JD$99md*D=,@A2FMMaQX[_Q_``r   c                 V   | j                  d|      \  }}t        j                  |      t        j                  |      }}||z
  dz  j                  d|      \  }}	||z  |	|z  z
  ||z  |	|z  z   }}
t        j                  |
|g|      |z   }t        j                  |||z   g|      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.

    Returns:
        (torch.Tensor): Predicted rotated bounding boxes with shape (bs, h*w, 4).
    rU   r   r   )r   r"   cossinr   )	pred_dist
pred_angler   r6   r   r   r   r   xfyfxyxys                r   	dist2rboxr     s     __QC_(FByy$eii
&;CBw!m""1#".FB8b3hS28 3qA	Aq6s	#m	3B99b"r'],,r   )g      ?)Tr5   )r5   )r"   torch.nnnn r   checksr   rq   r   r   opsr   __version__r   Moduler
   r   r   r   r   r   r   r   r   <module>r      sc       ! & 5,,h7
{0")) {0|	 e!4  eF>	(a-r   