
    hQ                         S SK r S SKJr  SSKJr  SSKJrJr  SSKJ	r	  SSK
Jr   " S S\R                  5      r " S	 S
\5      rSS jrSS jrS rSS jrg)    N   )LOGGER)bbox_iouprobiou)xywhr2xyxyxyxy)
TORCH_1_11c                      ^  \ rS rSrSrSS\S\S\S\S\4
U 4S jjjr\R                  " 5       S	 5       r
S
 rS rS rS rSS jrS r\SS j5       r\S 5       rSrU =r$ )TaskAlignedAssigner   aG  
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                 ^   > [         TU ]  5         Xl        X l        X0l        X@l        XPl        g)a  
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         O/home/james-whalen/.local/lib/python3.13/site-packages/ultralytics/utils/tal.pyr   TaskAlignedAssigner.__init__   s*     		&
	    c                   ^
 UR                   S   U l        UR                   S   U l        UR                  m
U R                  S:X  a  [        R
                  " US   U R                  5      [        R                  " U5      [        R                  " U5      [        R                  " US   5      [        R                  " US   5      4$  U R                  XX4XV5      $ ! [        R                  R                   ae    [        R                  " S5        XX4XV4 Vs/ s H  owR                  5       PM     Os  snf nnU R                  " U6 n	[        U
4S jU	 5       5      s $ f = f)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   D   >#    U  H  oR                  T5      v   M     g 7fN)to).0tdevices     r   	<genexpr>.TaskAlignedAssigner.forward.<locals>.<genexpr>X   s     6v!fvs    )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   forwardTaskAlignedAssigner.forward-   s&   . //!$$??1-!!q 	& 143C3CD  +  +  6!23  6!23 	7==ziaazz** 	7NNTU-6:Zc,mn,mq557,mnKn]]K0F6v666	7s   C ;ED.-,EEc                 v   U R                  XXEX65      u  pxn	U R                  XyU R                  5      u  pnU R                  XEX5      u  pnX-  nUR	                  SSS9nX-  R	                  SSS9nUU-  XR
                  -   -  R	                  S5      R                  S5      nUU-  nXXR                  5       U
4$ )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/   r0   r1   r2   r3   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(   TaskAlignedAssigner._forwardZ   s    & ,0+<+<)
,
( ,0+G+G\`\l\l+m( 7;6F6Fy]j6t3m 	 (--"d-C +11b$1G)L8<MPXPX<XY__`bcmmnpq%(99]LLNMYYr   c                     U R                  XT5      nU R                  XX4Xv-  5      u  pU R                  XR                  SSU R                  5      R                  5       S9n
X-  U-  nXU	4$ )au  
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).
r9   )	topk_mask)select_candidates_in_gtsget_box_metricsselect_topk_candidatesexpandr   rB   )r   r.   r/   r1   r2   r0   r3   mask_in_gtsrD   rE   	mask_topkrC   s               r   r=    TaskAlignedAssigner.get_pos_mask   sy    " 33JJ!%!5!5iIbmbw!x//WY[]_c_h_hHiHnHnHp/q	*W4x//r   c                    UR                   S   nUR                  5       n[        R                  " U R                  U R
                  U/UR                  UR                  S9n[        R                  " U R                  U R
                  U/UR                  UR                  S9n[        R                  " SU R                  U R
                  /[        R                  S9n	[        R                  " U R                  S9R                  SS5      R                  SU R
                  5      U	S'   UR                  S5      U	S'   XS   S	S	2U	S   4   U   X'   UR                  S5      R                  SU R
                  SS5      U   n
UR                  S5      R                  SSUS5      U   nU R                  X5      Xu'   UR                  U R                   5      UR                  U R"                  5      -  nX4$ )
a  
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      )rZ   )endr9   r   r   N)r"   rB   r%   zerosr#   r$   rZ   r   longarangeviewrT   squeezerA   iou_calculationpowr   r   )r   r.   r/   r1   r2   r3   narE   bbox_scoresindpd_boxesgt_boxesrD   s                r   rR   #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 &&q)00T5E5Er2NwW&&q)00RR@I 00D"tzz2X\\$))5LL%%r   c                 T    [        XSSS9R                  S5      R                  S5      $ )z
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CIoUr9   r   )r   ra   clamp_r   r2   r/   s      r   rb   #TaskAlignedAssigner.iou_calculation   s*     	5tDLLRPWWXYZZr   c           
         [         R                  " XR                  SSS9u  p4Uc/  UR                  SSS9S   U R                  :  R	                  U5      nUR                  U) S5        [         R                  " UR                  [         R                  UR                  S9n[         R                  " USS2SS2SS24   [         R                  UR                  S9n[        U R                  5       H$  nUR                  SUSS2SS2XwS-   24   U5        M&     UR                  US:  S5        UR                  UR                  5      $ )	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.
r9   T)r:   largestN)r;   r   rY   r   )r%   r   maxr   	expand_asmasked_fill_r]   r"   int8r   	ones_likerangescatter_add_r   rZ   )r   metricsrP   topk_metrics	topk_idxscount_tensoronesks           r   rS   *TaskAlignedAssigner.select_topk_candidates   s    #(**WiiRQU"V%))"d);A>ITTU^_I	z1- {{7==

9K[K[\yArr2%**YM]M]^tyy!A%%b)Aq!!e)O*DdK " 	!!,"2A6w}}--r   c                    [         R                  " U R                  [         R                  UR                  S9S   nX5U R
                  -  -   nUR                  5       R                  5       U   nUR                  SUR                  S   5      U   nUR                  S5        [         R                  " UR                  S   UR                  S   U R                  4[         R                  UR                  S9nUR                  SUR                  S5      S5        USS2SS2S4   R                  SSU R                  5      n	[         R                   " U	S:  US5      nXgU4$ )	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).
)r\   rZ   r   ).Nr9   r   r   rY   r[   N)r%   r_   r#   int64r   r$   r^   flattenr`   r"   rm   r]   r   scatter_rA   repeatwhere)
r   r1   r2   rF   rG   	batch_indrH   rI   rJ   fg_scores_masks
             r   r?   TaskAlignedAssigner.get_targets   s3   ( 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]::r   c                 .   U R                   S   nUR                   u  pEnUR                  SSS5      R                  SS5      u  px[        R                  " U S   U-
  XS   -
  4SS9R                  XEUS5      n	U	R                  S5      R                  U5      $ )	a  
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   r9   r      r[   Nr:      )r"   r`   chunkr%   catamingt_)

xy_centersr2   r   	n_anchorsr#   n_boxes_ltrbbbox_deltass
             r   rQ   ,TaskAlignedAssigner.select_candidates_in_gts  s    " $$Q'	"QAq)//15iiD!1B!6=M8M NTUV[[\^irtvw"&&s++r   c                    U R                  S5      nUR                  5       S:  a  UR                  S5      S:  R                  SUS5      nUR	                  S5      n[
        R                  " U R                  U R                  U R                  S9nUR                  SUR                  S5      S5        [
        R                  " XFU 5      R                  5       n U R                  S5      nU R	                  S5      nXsU 4$ )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).
r<   r   r9   rY   )sumrr   rA   rT   argmaxr%   r]   r"   rZ   r   r   r   float)rC   rE   r$   rG   mask_multi_gtsmax_overlaps_idxis_max_overlapsrF   s           r   r>   +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 +x//r   )r   r   r#   r   r$   r   r   )   P   g      ?g      @&.>r   )r   )__name__
__module____qualname____firstlineno____doc__intr   r   r%   no_gradr6   r(   r=   rR   rb   rS   r?   staticmethodrQ   r>   __static_attributes____classcell__)r   s   @r   r
   r
      s    S C U X] jo  $ ]]_*7 *7X#ZJ06 &D[.@);V , ,, 0 0r   r
   c                   .    \ rS rSrSrS r\S 5       rSrg)RotatedTaskAlignedAssigneriJ  zSAssigns ground-truth objects to rotated bounding boxes using a task-aligned metric.c                 T    [        X5      R                  S5      R                  S5      $ )z)Calculate IoU for rotated bounding boxes.r9   r   )r   ra   rm   rn   s      r   rb   *RotatedTaskAlignedAssigner.iou_calculationM  s#    y,44R8??BBr   c                    [        U5      nUR                  SSS9u  p4pVXC-
  nXc-
  nX-
  n	Xw-  R                  SS9n
X-  R                  SS9nX-  R                  SS9nX-  R                  SS9nUS:  X:*  -  US:  -  X:*  -  $ )aM  
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   r9   r   )r   splitr   )r   r2   cornersabr   dabadapnorm_abnorm_ad	ap_dot_ab	ap_dot_ads                 r   rQ   3RotatedTaskAlignedAssigner.select_candidates_in_gtsQ  s     !+]]1"]-
aUU ^7--B-'7--B-'WMMbM)	WMMbM)	Q9#78INKyOcddr    N)	r   r   r   r   r   rb   r   rQ   r   r   r   r   r   r   J  s!    ]C e er   r   c           
         / / pCU c   eU S   R                   U S   R                  pe[        U5       GH  u  px[        U [        5      (       a  X   R
                  SS O[        X   S   5      [        X   S   5      4u  p[        R                  " XUS9U-   n[        R                  " XUS9U-   n[        (       a  [        R                  " XSS9O[        R                  " X5      u  pUR                  [        R                  " X4S5      R                  SS5      5        UR                  [        R                  " X-  S4XUS	95        GM     [        R                  " U5      [        R                  " U5      4$ )
zGenerate anchors from features.Nr   r[   r   )r\   r   rZ   ij)indexingr9   rY   )rZ   r   	enumerate
isinstancelistr"   r   r%   r_   r   meshgridappendstackr`   fullr   )featsstridesgrid_cell_offsetanchor_pointsstride_tensorrZ   r   istridehwsxsys                r   make_anchorsr   m  s7   #%r=!HNNE!HOO6w'	%/t%<%<ux~~ab!3uxPQ{CSUXY^YabcYdUeBf\\ae<?OO\\ae<?OO:D*6%..Y[J`U[["26;;BBCUZZ
FPVWX ( 99]#UYY}%===r   c                     U R                  SU5      u  pEX-
  nX-   nU(       a#  Xg-   S-  nXv-
  n	[        R                  " X/U5      $ [        R                  " Xg4U5      $ )z.Transform distance(ltrb) to box(xywh or xyxy).r[   )r   r%   r   )
distancer   rk   r:   r   r   x1y1x2y2c_xywhs
             r   	dist2bboxr   |  s`    ^^As#FBDDq [yy$S))99d\3''r   c                     UR                  SS5      u  p4[        R                  " X-
  X@-
  4S5      R                  SUS-
  5      $ )z#Transform bbox(xyxy) to dist(ltrb).r[   r9   r   g{Gz?)r   r%   r   rm   )r   bboxreg_maxr   r   s        r   	bbox2distr     sD    Ar"JD99m*D,@A2FMMaQX[_Q_``r   c                 0   U R                  SUS9u  pE[        R                  " U5      [        R                  " U5      pvXT-
  S-  R                  SUS9u  pX-  X-  -
  X-  X-  -   p[        R                  " X/US9U-   n[        R                  " XU-   /US9$ )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).
r[   r   r   )r   r%   cossinr   )	pred_dist
pred_angler   r:   r   r   r   r   xfyfxyxys                r   	dist2rboxr     s     __QC_(FByy$eii
&;w!m""1#".FB8bh28 3q	A6s	#m	3B99br'],,r   )g      ?)Tr9   )r9   )r%   torch.nnnn r   ry   r   r   opsr   torch_utilsr   Moduler
   r   r   r   r   r   r   r   r   <module>r      sQ       &  #{0")) {0|	 e!4  eF>	(a-r   