o
    Wh߇                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlm	  m
Z d dlmZ d dlmZ G dd de jZdQddZdRddZdd ZdSddZ				
	
			 						
	
	
dTddZdd Zdd ZdUddZd d! Zd"d# ZdVd$d%ZdWd'd(Zd)d* Zd+d, Zd-d. Z d/d0 Z!d1d2 Z"d3d4 Z#d5d6 Z$dXd8d9Z%d:d; Z&dYd<d=Z'd>d? Z(dZd@dAZ)d[dBdCZ*dDdE Z+d\dGdHZ,dIej-dJej.fdKdLZ/dMdN Z0dOdP Z1dS )]    N)LOGGER)batch_probiouc                   @   sB   e Zd ZdZddejfddZdd Zd	d
 Zdd Z	dd Z
dS )Profilea  
    YOLOv8 Profile class. Use as a decorator with @Profile() or as a context manager with 'with Profile():'.

    Attributes:
        t (float): Accumulated time.
        device (torch.device): Device used for model inference.
        cuda (bool): Whether CUDA is being used.

    Examples:
        >>> from ultralytics.utils.ops import Profile
        >>> with Profile(device=device) as dt:
        ...     pass  # slow operation here
        >>> print(dt)  # prints "Elapsed time is 9.5367431640625e-07 s"
            Ndevicec                 C   s(   || _ || _t|ot|d| _dS )z
        Initialize the Profile class.

        Args:
            t (float): Initial time.
            device (torch.device): Device used for model inference.
        cudaN)tr   boolstr
startswithr   )selfr   r    r   I/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/utils/ops.py__init__!   s   zProfile.__init__c                 C   s   |   | _| S )zStart timing.)timestartr   r   r   r   	__enter__-   s   
zProfile.__enter__c                 C   s$   |   | j | _|  j| j7  _dS )zStop timing.N)r   r   dtr   )r   typevalue	tracebackr   r   r   __exit__2   s   zProfile.__exit__c                 C   s   d| j  dS )zZReturns a human-readable string representing the accumulated elapsed time in the profiler.zElapsed time is z s)r   r   r   r   r   __str__7   s   zProfile.__str__c                 C   s   | j r
tj | j t S )zGet current time.)r   torchsynchronizer   r   perf_counterr   r   r   r   r   ;   s   zProfile.time)r   N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   r   r      s    r     c                 C   s   | j \}}t| dk | dk | |k| |kg dkr.|d|}|d|}|dk|dk@ ||k@ ||k@ }|| }|| }t|r^tj| | | | g| jdS tj	d| jdS )ah  
    Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy).

    Args:
        segment (torch.Tensor): The segment label.
        width (int): The width of the image.
        height (int): The height of the image.

    Returns:
        (np.ndarray): The minimum and maximum x and y values of the segment.
    r      dtype   )
Tnparrayminmaxsumclipanyr$   zeros)segmentwidthheightxyinsider   r   r   segment2boxB   s   
: (r5   TFc                 C   s   |du r6t | d |d  | d |d  }t| d |d |  d d t| d |d |  d d f}n
|d d }|d }|rl|d  |d 8  < |d  |d 8  < |sl|d  |d 8  < |d	  |d 8  < |d
ddf  |  < t||S )av  
    Rescale bounding boxes from img1_shape to img0_shape.

    Args:
        img1_shape (tuple): The shape of the image that the bounding boxes are for, in the format of (height, width).
        boxes (torch.Tensor): The bounding boxes of the objects in the image, in the format of (x1, y1, x2, y2).
        img0_shape (tuple): The shape of the target image, in the format of (height, width).
        ratio_pad (tuple): A tuple of (ratio, pad) for scaling the boxes. If not provided, the ratio and pad will be
            calculated based on the size difference between the two images.
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.
        xywh (bool): The box format is xywh or not.

    Returns:
        (torch.Tensor): The scaled bounding boxes, in the format of (x1, y1, x2, y2).
    Nr         g?.r   .r6   .r7   .r"   .r%   )r)   round
clip_boxes)
img1_shapeboxes
img0_shape	ratio_padpaddingxywhgainpadr   r   r   scale_boxes]   s   "
rF   c                 C   s*   t |tjrt| }t| | | S )a  
    Returns the nearest number that is divisible by the given divisor.

    Args:
        x (int): The number to make divisible.
        divisor (int | torch.Tensor): The divisor.

    Returns:
        (int): The nearest number divisible by the divisor.
    )
isinstancer   Tensorintr*   mathceil)r2   divisorr   r   r   make_divisible   s   rM   ?c                 C   s   t j|dd}| | } t| | }|r+|jdd}t ||kddkd}|| S | jd }t j|| j	d
ddd|}t j|| j	d
dd|d}	||	k }
||
 }d|||kddk < t ||jd j}|| S )a	  
    NMS for oriented bounding boxes using probiou and fast-nms.

    Args:
        boxes (torch.Tensor): Rotated bounding boxes, shape (N, 5), format xywhr.
        scores (torch.Tensor): Confidence scores, shape (N,).
        threshold (float): IoU threshold.
        use_triu (bool): Whether to use `torch.triu` operator. It'd be useful for disable it
            when exporting obb models to some formats that do not support `torch.triu`.

    Returns:
        (torch.Tensor): Indices of boxes to keep after NMS.
    T
descendingr6   )diagonalr   r   )r   argsortr   triu_nonzeror+   squeeze_shapearanger   viewexpandtopkindices)r?   scores	thresholduse_triu
sorted_idxiouspicknrow_idxcol_idx
upper_maskr   r   r   nms_rotated   s   

  rh         ?r   ,  皙?0u     c           *         s4  ddl }d  krdksn J d dd|  kr!dks*n J d| dtttfr5d  durAtj jd jd d	ksJ|rcfd
dD } dura fdd|D }|S jd }|ppjd d }jd | d }d| }ddd|f dk}t	fdd|D d }d|	|  }||dkM }
dd|s|rtdddf dddf< ntjtdddf dddf fddt }tjdd	| fjdg| }tjdjdg| }tt|D ]\}\}}|| }|| || }}|rct|| rc|sc|| }tjt||| d f|jd}t|ddddf |ddddf< d|tt||dddf  d f< t||fd}|jd sjq|d||fd\} }!}"|rt|!k\}#}$t| |# ||#d|$ df |$dddf  |"|# fd}||# }n"|!jddd\}%}$|%dk}t| |%|$ |"fd| }|| } dur|dddd	f  kd}|| || }}|jd }&|&sq|&|
kr
|dddf jddd|
 }|| || }}|dddd	f |rdn| }'|dddf }(|rQtj|ddddf |' |ddddf |ddddf fdd})t|)|(|}#n|ddddf |' })|j|)|(|}#|#d }#||# ||# d||< ||< t | |krt d|dd  nq|r||fS |S )a  
    Perform non-maximum suppression (NMS) on a set of boxes, with support for masks and multiple labels per box.

    Args:
        prediction (torch.Tensor): A tensor of shape (batch_size, num_classes + 4 + num_masks, num_boxes)
            containing the predicted boxes, classes, and masks. The tensor should be in the format
            output by a model, such as YOLO.
        conf_thres (float): The confidence threshold below which boxes will be filtered out.
            Valid values are between 0.0 and 1.0.
        iou_thres (float): The IoU threshold below which boxes will be filtered out during NMS.
            Valid values are between 0.0 and 1.0.
        classes (List[int]): A list of class indices to consider. If None, all classes will be considered.
        agnostic (bool): If True, the model is agnostic to the number of classes, and all
            classes will be considered as one.
        multi_label (bool): If True, each box may have multiple labels.
        labels (List[List[Union[int, float, torch.Tensor]]]): A list of lists, where each inner
            list contains the apriori labels for a given image. The list should be in the format
            output by a dataloader, with each label being a tuple of (class_index, x1, y1, x2, y2).
        max_det (int): The maximum number of boxes to keep after NMS.
        nc (int): The number of classes output by the model. Any indices after this will be considered masks.
        max_time_img (float): The maximum time (seconds) for processing one image.
        max_nms (int): The maximum number of boxes into torchvision.ops.nms().
        max_wh (int): The maximum box width and height in pixels.
        in_place (bool): If True, the input prediction tensor will be modified in place.
        rotated (bool): If Oriented Bounding Boxes (OBB) are being passed for NMS.
        end2end (bool): If the model doesn't require NMS.
        return_idxs (bool): Return the indices of the detections that were kept.

    Returns:
        (List[torch.Tensor]): A list of length batch_size, where each element is a tensor of
            shape (num_boxes, 6 + num_masks) containing the kept boxes, with columns
            (x1, y1, x2, y2, confidence, class, mask1, mask2, ...).
    r   Nr6   zInvalid Confidence threshold z&, valid values are between 0.0 and 1.0zInvalid IoU rS   rR      c                    s,   g | ]}||d d df  k d  qS )Nr%   r   .0pred)
conf_thresmax_detr   r   
<listcomp>   s   , z'non_max_suppression.<locals>.<listcomp>c                    s.   g | ]}||d d ddf  k d qS )N   rn   r6   )r-   ro   )classesr   r   rt      s   . r%   c                    s    g | ]}t jt| jd qS )rS   )r   rY   lenr   rp   i)
predictionr   r   rt      s     ).Ng       @.dim)r   r6   ru   g      ?T)keepdimrO   r7   zNMS time limit z.3fz
s exceeded)!torchvisionrG   listtupler   tensorr   rX   amaxstack	transpose	xywh2xyxycatr   r.   	enumerateziprw   rangelongsplitwherefloatr*   rZ   r-   rT   rh   opsnmsreshaper   warning)*rz   rr   	iou_thresrv   agnosticmulti_labellabelsrs   ncmax_time_imgmax_nmsmax_whin_placerotatedend2endreturn_idxsr   outputbsnmmixcxinds
time_limitr   keepixir2   xkfiltlbvboxclsmaskry   jconfrd   cr^   r?   r   )rv   rr   rs   rz   r   non_max_suppression   s   3&&
". ((:



 "H r   c                 C   s   t | tjr8| d d|d | d< | d d|d | d< | d d|d | d< | d d|d | d< | S | dddgf d|d | dddgf< | ddd	gf d|d | ddd	gf< | S )
a<  
    Takes a list of bounding boxes and a shape (height, width) and clips the bounding boxes to the shape.

    Args:
        boxes (torch.Tensor | numpy.ndarray): The bounding boxes to clip.
        shape (tuple): The shape of the image.

    Returns:
        (torch.Tensor | numpy.ndarray): The clipped boxes.
    r8   r   r6   r9   r:   r;   .r7   r"   rG   r   rH   clampr,   )r?   rX   r   r   r   r=   Y  s   ((r=   c                 C   st   t | tjr | d d|d | d< | d d|d | d< | S | d d|d | d< | d d|d | d< | S )aF  
    Clip line coordinates to the image boundaries.

    Args:
        coords (torch.Tensor | numpy.ndarray): A list of line coordinates.
        shape (tuple): A tuple of integers representing the size of the image in the format (height, width).

    Returns:
        (torch.Tensor | numpy.ndarray): Clipped coordinates.
    r8   r   r6   r9   r   )coordsrX   r   r   r   clip_coordso  s   r   c           
      C   s@  | j }|dd |dd kr| S |du r?t|d |d  |d |d  }|d |d |  d |d |d |  d f}n|d }t|d t|d }}t|d |d  t|d |d  }}	t| j dk rvtdt| j  | ||||	f } t| |d |d f} t| j dkr| dddddf } | S )a  
    Takes a mask, and resizes it to the original image size.

    Args:
        masks (np.ndarray): Resized and padded masks/images, [h, w, num]/[h, w, 3].
        im0_shape (tuple): The original image shape.
        ratio_pad (tuple): The ratio of the padding to the original image.

    Returns:
        masks (np.ndarray): The masks that are being returned with shape [h, w, num].
    Nr7   r   r6   z/"len of masks shape" should be 2 or 3, but got )rX   r)   rI   rw   
ValueErrorcv2resize)
masks	im0_shaperA   	im1_shaperD   rE   topleftbottomrightr   r   r   scale_image  s    "2*r   c                 C   s   | j d dksJ d| j  t| }| d | d  d |d< | d | d  d |d< | d | d  |d< | d | d  |d< |S )	a  
    Convert bounding box coordinates from (x1, y1, x2, y2) format to (x, y, width, height) format where (x1, y1) is the
    top-left corner and (x2, y2) is the bottom-right corner.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height) format.
    rR   r%   9input shape last dimension expected 4 but input shape is r8   r:   r7   r9   r;   rX   
empty_liker2   r3   r   r   r   	xyxy2xywh  s   r   c                 C   sv   | j d dksJ d| j  t| }| dddf }| dddf d }|| |dddf< || |dddf< |S )a  
    Convert bounding box coordinates from (x, y, width, height) format to (x1, y1, x2, y2) format where (x1, y1) is the
    top-left corner and (x2, y2) is the bottom-right corner. Note: ops per 2 channels faster than per channel.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x, y, width, height) format.

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x1, y1, x2, y2) format.
    rR   r%   r   .Nr7   r   )r2   r3   xywhr   r   r   r     s   r   c                 C   s   | j d dksJ d| j  t| }|| d | d d   | |d< || d | d d   | |d< || d | d d   | |d< || d | d d   | |d< |S )	a  
    Convert normalized bounding box coordinates to pixel coordinates.

    Args:
        x (np.ndarray | torch.Tensor): The bounding box coordinates.
        w (int): Width of the image.
        h (int): Height of the image.
        padw (int): Padding width.
        padh (int): Padding height.

    Returns:
        y (np.ndarray | torch.Tensor): The coordinates of the bounding box in the format [x1, y1, x2, y2] where
            x1,y1 is the top-left corner, x2,y2 is the bottom-right corner of the bounding box.
    rR   r%   r   r8   r:   r7   r9   r;   r   )r2   whpadwpadhr3   r   r   r   
xywhn2xyxy  s       r   r   c                 C   s   |rt | || || f} | jd dksJ d| j t| }| d | d  d | |d< | d | d  d | |d< | d | d  | |d< | d | d  | |d< |S )	a  
    Convert bounding box coordinates from (x1, y1, x2, y2) format to (x, y, width, height, normalized) format. x, y,
    width and height are normalized to image dimensions.

    Args:
        x (np.ndarray | torch.Tensor): The input bounding box coordinates in (x1, y1, x2, y2) format.
        w (int): The width of the image.
        h (int): The height of the image.
        clip (bool): If True, the boxes will be clipped to the image boundaries.
        eps (float): The minimum value of the box's width and height.

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height, normalized) format
    rR   r%   r   r8   r:   r7   r9   r;   )r=   rX   r   )r2   r   r   r,   epsr3   r   r   r   
xyxy2xywhn  s   r   c                 C   sR   t | tjr
|  nt| }| d | d d  |d< | d | d d  |d< |S )aX  
    Convert the bounding box format from [x, y, w, h] to [x1, y1, w, h], where x1, y1 are the top-left coordinates.

    Args:
        x (np.ndarray | torch.Tensor): The input tensor with the bounding box coordinates in the xywh format

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xyltwh format
    r8   r:   r7   r9   r;   rG   r   rH   cloner'   copyr   r   r   r   	xywh2ltwh      
r   c                 C   sJ   t | tjr
|  nt| }| d | d  |d< | d | d  |d< |S )aU  
    Convert nx4 bounding boxes from [x1, y1, x2, y2] to [x1, y1, w, h], where xy1=top-left, xy2=bottom-right.

    Args:
        x (np.ndarray | torch.Tensor): The input tensor with the bounding boxes coordinates in the xyxy format

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xyltwh format.
    r:   r8   r;   r9   r   r   r   r   r   	xyxy2ltwh     
r   c                 C   sR   t | tjr
|  nt| }| d | d d  |d< | d | d d  |d< |S )z
    Convert nx4 boxes from [x1, y1, w, h] to [x, y, w, h] where xy1=top-left, xy=center.

    Args:
        x (torch.Tensor): the input tensor

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in the xywh format.
    r8   r:   r7   r9   r;   r   r   r   r   r   	ltwh2xywh   r   r   c           
   	   C   s   t | tj}|r|   n| }|t| dd}g }|D ]}t|\\}}\}}}	|	|||||	d t
j g q|rGtj|| j| jdS t
|S )a  
    Convert batched Oriented Bounding Boxes (OBB) from [xy1, xy2, xy3, xy4] to [xywh, rotation]. Rotation values are
    returned in radians from 0 to pi/2.

    Args:
        x (numpy.ndarray | torch.Tensor): Input box corners [xy1, xy2, xy3, xy4] of shape (n, 8).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted data in [cx, cy, w, h, rotation] format of shape (n, 5).
    rR   r7      r   r$   )rG   r   rH   cpunumpyr   rw   r   minAreaRectappendr'   pir   r   r$   asarray)
r2   is_torchpointsrboxesptscxcyr   r   angler   r   r   xyxyxyxy2xywhr0  s    "r   c                    s  t  tjrtjtjtjtjfn	tjtjtjtjf\}}}} dddf } fddt	ddD \}}}||||}	}
|d |	 |d |
 g}| d |
 |d |	 g}||d}||d}|| | }|| | }|| | }|| | }|||||gdS )	a  
    Convert batched Oriented Bounding Boxes (OBB) from [xywh, rotation] to [xy1, xy2, xy3, xy4]. Rotation values should
    be in radians from 0 to pi/2.

    Args:
        x (numpy.ndarray | torch.Tensor): Boxes in [cx, cy, w, h, rotation] format of shape (n, 5) or (b, n, 5).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted corner points of shape (n, 4, 2) or (b, n, 4, 2).
    .Nr7   c                 3   s$    | ]} d ||d f V  qdS ).r6   Nr   rx   r2   r   r   	<genexpr>Y  s   " z!xywhr2xyxyxyxy.<locals>.<genexpr>ru   rR   r{   )
rG   r   rH   cossinr   r   r'   concatenater   )r2   r   r   r   r   ctrr   r   r   	cos_value	sin_valuevec1vec2pt1pt2pt3pt4r   r   r   xywhr2xyxyxyxyG  s    



r   c                 C   sJ   t | tjr
|  nt| }| d | d  |d< | d | d  |d< |S )a  
    Convert bounding box from [x1, y1, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right.

    Args:
        x (np.ndarray | torch.Tensor): The input image.

    Returns:
        (np.ndarray | torch.Tensor): The xyxy coordinates of the bounding boxes.
    r:   r8   r;   r9   r   r   r   r   r   	ltwh2xyxyf  r   r   c                 C   sH   g }| D ]}|j \}}|| | | | g qtt|S )a+  
    Convert segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh).

    Args:
        segments (list): List of segments, each segment is a list of points, each point is a list of x, y coordinates.

    Returns:
        (np.ndarray): The xywh coordinates of the bounding boxes.
    )r&   r   r)   r*   r   r'   r(   )segmentsr?   sr2   r3   r   r   r   segments2boxesv  s
   

$r     c                    s   t | D ]g\} t |krqtj  ddddf fdd tdt d t |k r4|t  n|tt t |k rOttntj fddtdD tj	d
dd	j| |< q| S )
aT  
    Inputs a list of segments (n,2) and returns a list of segments (n,2) up-sampled to n points each.

    Args:
        segments (list): A list of (n,2) arrays, where n is the number of points in the segment.
        n (int): Number of points to resample the segment to.

    Returns:
        segments (list): The resampled segments.
    r   r6   N)axisc              	      s&   g | ]}t  d d |f qS N)r'   interprx   r   r2   xpr   r   rt     s   & z%resample_segments.<locals>.<listcomp>r7   r#   rR   )r   rw   r'   r   linspacerY   insertsearchsortedr   float32r   r&   )r   rd   ry   r   r   r   resample_segments  s   ".&.r  c                 C   s   | j \}}}t|dddddf dd\}}}}tj|| j|jdddddf }	tj|| j|jdddddf }
| |	|k|	|k  |
|k |
|k   S )z
    Crop masks to bounding boxes.

    Args:
        masks (torch.Tensor): [n, h, w] tensor of masks.
        boxes (torch.Tensor): [n, 4] tensor of bbox coordinates in relative point form.

    Returns:
        (torch.Tensor): Cropped masks.
    Nr%   r6   r   )rX   r   chunkrY   r   r$   )r   r?   _r   r   x1y1x2y2rr   r   r   r   	crop_mask  s
   (""$r  c                 C   s   | j \}}}|\}}	||  |d d||}
||	 }|| }| }|dddf  |9  < |dddf  |9  < |dddf  |9  < |dddf  |9  < t|
|}
|ritj|
d |ddd	d }
|
d
S )a)  
    Apply masks to bounding boxes using the output of the mask head.

    Args:
        protos (torch.Tensor): A tensor of shape [mask_dim, mask_h, mask_w].
        masks_in (torch.Tensor): A tensor of shape [n, mask_dim], where n is the number of masks after NMS.
        bboxes (torch.Tensor): A tensor of shape [n, 4], where n is the number of masks after NMS.
        shape (tuple): A tuple of integers representing the size of the input image in the format (h, w).
        upsample (bool): A flag to indicate whether to upsample the mask to the original image size.

    Returns:
        (torch.Tensor): A binary mask tensor of shape [n, h, w], where n is the number of masks after NMS, and h and w
            are the height and width of the input image. The mask is applied to the bounding boxes.
    rR   Nr   r7   r"   r6   bilinearFmodealign_cornersr   )rX   r   rZ   r   r  Finterpolategt_)protosmasks_inbboxesrX   upsampler   mhmwihiwr   width_ratioheight_ratiodownsampled_bboxesr   r   r   process_mask  s   

r   c                 C   sP   | j \}}}||  |d d||}t|d |d }t||}|dS )a  
    Apply masks to bounding boxes using the output of the mask head with native upsampling.

    Args:
        protos (torch.Tensor): [mask_dim, mask_h, mask_w].
        masks_in (torch.Tensor): [n, mask_dim], n is number of masks after nms.
        bboxes (torch.Tensor): [n, 4], n is number of masks after nms.
        shape (tuple): The size of the input image (h,w).

    Returns:
        (torch.Tensor): The returned masks with dimensions [h, w, n].
    rR   Nr   r   )rX   r   rZ   scale_masksr  r  )r  r  r  rX   r   r  r  r   r   r   r   process_mask_native  s
   

r"  c                 C   s   | j dd \}}t||d  ||d  }||d |  ||d |  g}|r8|d  d  < |d  d  < |rFt|d t|d fnd\}}t||d  t||d  }	}
| d||	||
f } tj| |ddd	} | S )
aN  
    Rescale segment masks to shape.

    Args:
        masks (torch.Tensor): (N, C, H, W).
        shape (tuple): Height and width.
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.

    Returns:
        (torch.Tensor): Rescaled masks.
    r7   Nr   r6   )r   r   .r  Fr  )rX   r)   rI   r  r  )r   rX   rB   r  r  rD   rE   r   r   r   r   r   r   r   r!    s    $"r!  c                 C   s   |du r.t | d |d  | d |d  }| d |d |  d | d |d |  d f}n
|d d }|d }|rN|d  |d 8  < |d  |d 8  < |d  |  < |d  |  < t||}|ry|d  |d   < |d  |d   < |S )a  
    Rescale segment coordinates (xy) from img1_shape to img0_shape.

    Args:
        img1_shape (tuple): The shape of the image that the coords are from.
        coords (torch.Tensor): The coords to be scaled of shape n,2.
        img0_shape (tuple): The shape of the image that the segmentation is being applied to.
        ratio_pad (tuple): The ratio of the image size to the padded image size.
        normalize (bool): If True, the coordinates will be normalized to the range [0, 1].
        padding (bool): If True, assuming the boxes is based on image augmented by yolo style. If False then do regular
            rescaling.

    Returns:
        coords (torch.Tensor): The scaled coordinates.
    Nr   r6   r7   r8   r9   )r)   r   )r>   r   r@   rA   	normalizerB   rD   rE   r   r   r   scale_coords  s   "2
r$  c           	      C   sl   | j dd\}}}}}|tj tjd k}t|||}t|||}|tjd  }tj|||||gddS )z
    Regularize rotated boxes in range [0, pi/2].

    Args:
        rboxes (torch.Tensor): Input boxes of shape(N, 5) in xywhr format.

    Returns:
        (torch.Tensor): The regularized boxes.
    rR   r|   r7   )unbindrJ   r   r   r   r   )	r   r2   r3   r   r   r   swapw_h_r   r   r   regularize_rboxes%  s   
r)  allc                 C   s   ddl m} g }|    dD ]U}t|tjtj	d }|r[|dkrAt
|dkr8t|dd |D n|d dd	}n|d
krZt|tdd |D   dd	}ntd}||d q|S )z
    Convert masks to segments.

    Args:
        masks (torch.Tensor): The output of the model, which is a tensor of shape (batch_size, 160, 160).
        strategy (str): 'all' or 'largest'.

    Returns:
        (list): List of segment masks.
    r   )merge_multi_segmentuint8r*  r6   c                 S   s   g | ]}| d dqS )rR   r7   )r   rp   r2   r   r   r   rt   K  s    z"masks2segments.<locals>.<listcomp>rR   r7   largestc                 S   s   g | ]}t |qS r   )rw   r-  r   r   r   rt   P  s    )r   r7   r  )ultralytics.data.converterr+  rI   r   r   astyper   findContoursRETR_EXTERNALCHAIN_APPROX_SIMPLErw   r'   r   r   r(   argmaxr.   r   )r   strategyr+  r   r2   r   r   r   r   masks2segments8  s    *
r6  batchreturnc                 C   s0   |  dddd d ddtj  S )as  
    Convert a batch of FP32 torch tensors (0.0-1.0) to a NumPy uint8 array (0-255), changing from BCHW to BHWC layout.

    Args:
        batch (torch.Tensor): Input tensor batch of shape (Batch, Channels, Height, Width) and dtype torch.float32.

    Returns:
        (np.ndarray): Output NumPy array batch of shape (Batch, Height, Width, Channels) and dtype uint8.
    r   r7   r"   r6      )permute
contiguousr   tor   r,  r   r   )r7  r   r   r   convert_torch2numpy_batchW  s   0
r=  c                 C   s   t jdd| dS )z
    Cleans a string by replacing special characters with '_' character.

    Args:
        s (str): A string needing special characters replaced.

    Returns:
        (str): A string with special characters replaced by an underscore _.
    u"   [|@#!¡·$€%&()=?¿^*;:,¨´><+]r  )patternreplstring)resub)r   r   r   r   	clean_strd  s   
rC  c                 C   s,   t | tjrtj| tjdS tj| tjdS )zTCreates empty torch.Tensor or np.ndarray with same shape as input and float32 dtype.r#   )rG   r   rH   r   r  r'   r   r   r   r   r   q  s   r   )r!   r!   )NTF)rN   T)ri   rN   NFFr   rj   r   rk   rl   rm   TFFFr   )r!   r!   r   r   )r!   r!   Fr   )r   )F)T)NFT)r*  )2
contextlibrJ   rA  r   r   r   r'   r   torch.nn.functionalnn
functionalr  ultralytics.utilsr   ultralytics.utils.metricsr   ContextDecoratorr   r5   rF   rM   rh   r   r=   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r"  r!  r$  r)  r6  rH   ndarrayr=  rC  r   r   r   r   r   <module>   sr   
1
%
%
 %
#



!

#
