a
    yfx                     @   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dNddZdOddZdd ZdPddZdQddZdd Zdd ZdRddZd d! Zd"d# ZdSd$d%ZdTd'd(Zd)d* Zd+d, Zd-d. Z d/d0 Z!d1d2 Z"d3d4 Z#d5d6 Z$dUd8d9Z%d:d; Z&dVd<d=Z'd>d? Z(dWd@dAZ)dXdBdCZ*dDdE Z+dYdGdHZ,ej-ej.dIdJdKZ/dLdM Z0dS )Z    N)LOGGER)batch_probiouc                   @   sB   e Zd ZdZdejdddZdd Zd	d
 Zdd Z	dd Z
dS )Profileai  
    YOLOv8 Profile class. Use as a decorator with @Profile() or as a context manager with 'with Profile():'.

    Example:
        ```python
        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. Defaults to 0.0.
            device (torch.device): Devices used for model inference. Defaults to None (cpu).
        cudaN)tr   boolstr
startswithr   )selfr	   r    r   Q/var/www/html/django/DPS/env/lib/python3.9/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__1   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__6   s    zProfile.__str__c                 C   s   | j rtj | j t S )zGet current time.)r   torchZsynchronizer   r   r   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   sz   | j \}}|dk|dk@ ||k@ ||k@ }|| }|| }t|rjtj| | | | g| jdS tjd| jdS )a  
    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. Defaults to 640
        height (int): The height of the image. Defaults to 640

    Returns:
        (np.ndarray): the minimum and maximum x and y values of the segment.
    r   dtype   )Tanynparrayminmaxr"   zeros)segmentwidthheightxyZinsider   r   r   segment2boxA   s    
 *r0   TFc                 C   s   |du rlt | d |d  | d |d  }t| d |d |  d d t| d |d |  d d f}n|d d }|d }|r|d  |d 8  < |d  |d 8  < |s|d  |d 8  < |d	  |d 8  < |d
ddf  |  < t||S )a  
    Rescales bounding boxes (in the format of xyxy by default) from the shape of the image they were originally
    specified in (img1_shape) to the shape of a different image (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, default=False.

    Returns:
        boxes (torch.Tensor): The scaled bounding boxes, in the format of (x1, y1, x2, y2)
    Nr         g?.r   .r1   .r2   .   .r#   )r(   round
clip_boxes)
img1_shapeboxes
img0_shape	ratio_padpaddingZxywhgainpadr   r   r   scale_boxesX   s    "rA   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)r.   Zdivisorr   r   r   make_divisible~   s    rG   ?c                 C   sl   t | dkrtjdtjdS tj|dd}| | } t| | jdd}t|j	ddd |k 
d	}|| S )
ap  
    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, optional): IoU threshold. Defaults to 0.45.

    Returns:
        (torch.Tensor): Indices of boxes to keep after NMS.
    r   )r   r!   TZ
descendingr1   )Zdiagonaldim)lenr&   emptyZint8r   argsortr   Ztriu_Znonzeror)   Zsqueeze_)r;   scores	thresholdZ
sorted_idxZiouspickr   r   r   nms_rotated   s     rS         ?r   ,  皙?0u     c           $         s  ddl }d  krdks.n J d dd|  krBdksTn J d| dt| ttfrj| d }  durtj | jd | jd d	krfd
d| D } dur fdd|D }|S | jd }|p| jd d }| jd | d }d| }| ddd|f dk}d|	|  }||dkM }| 	dd} |s|rht
| 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| D ]\}}|||  }|r|t|| r||s||| }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 sq|d||fd\}}}|rt|k\}}t|| ||d| df |dddf  || fd}n8|jddd\}}t||| |fd|dk } dur\||dddd	f  kd }|jd } | spq| |
kr||dddf jddd|
  }|dddd	f |rdn| }!|dddf }"|r,t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 }|| ||< t | |krtd|dd  qq|S )aO  
    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, optional): 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.

    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   Nr1   zInvalid Confidence threshold z&, valid values are between 0.0 and 1.0zInvalid IoU r   rL      c                    s,   g | ]$}||d d df  k d  qS )Nr#   r   .0pred)
conf_thresmax_detr   r   
<listcomp>       z'non_max_suppression.<locals>.<listcomp>c                    s.   g | ]&}||d d ddf  k d qS )N   rY   r1   )r%   rZ   )classesr   r   r_      r`   r#   g       @.rJ   ra   g      ?T)ZkeepdimrI   r2   u   WARNING ⚠️ NMS time limit z.3fz
s exceeded)torchvisionrB   listtupler   tensorr   shapeZamaxZ	transpose	xywh2xyxycatr   r*   	enumeraterM   rangelongsplitwherefloatr)   viewr%   rO   rS   opsZnmsr   warning)$Z
predictionr]   Z	iou_thresrb   ZagnosticZmulti_labellabelsr^   ncZmax_time_imgZmax_nmsZmax_whZin_placeZrotatedrd   outputbsnmmiZxcZ
time_limitr	   xir.   ZlbvboxclsmaskijconfncrP   r;   r   )rb   r]   r^   r   non_max_suppression   s|    /&&
". ((<&
"

$"H
r   c                 C   s   t | tjrn| d d|d | d< | d d|d | d< | d d|d | d< | d d|d | d< nP| 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): the bounding boxes to clip
        shape (tuple): the shape of the image

    Returns:
        (torch.Tensor | numpy.ndarray): Clipped boxes
    r3   r   r1   r4   r5   r6   .r2   r7   rB   r   rC   clampclip)r;   rh   r   r   r   r9   ;  s    ((r9   c                 C   sr   t | tjr>| d d|d | d< | d d|d | d< n0| d d|d | d< | d d|d | d< | S )aE  
    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
    r3   r   r1   r4   r   )coordsrh   r   r   r   clip_coordsQ  s    r   c           
      C   sB  | 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 rt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].
    Nr2   r   r1   z/"len of masks shape" should be 2 or 3, but got )rh   r(   rD   rM   
ValueErrorcv2resize)
masksZ	im0_shaper=   Z	im1_shaper?   r@   topleftbottomrightr   r   r   scale_imagee  s     "2*r   c                 C   s   | j d dksJ d| j  t| tjr4t| n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.
    rL   r#   9input shape last dimension expected 4 but input shape is r3   r5   r2   r4   r6   rh   rB   r   rC   
empty_liker&   r.   r/   r   r   r   	xyxy2xywh  s     r   c                 C   s   | j d dksJ d| j  t| tjr4t| n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.
    rL   r#   r   .Nr2   r   )r.   r/   ZxyZwhr   r   r   ri     s     ri   c                 C   s   | j d dksJ d| j  t| tjr4t| nt| }|| d | d d   | |d< || d | d d   | |d< || d | d d   | |d< || d | d d   | |d< |S )	aF  
    Convert normalized bounding box coordinates to pixel coordinates.

    Args:
        x (np.ndarray | torch.Tensor): The bounding box coordinates.
        w (int): Width of the image. Defaults to 640
        h (int): Height of the image. Defaults to 640
        padw (int): Padding width. Defaults to 0
        padh (int): Padding height. Defaults to 0
    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.
    rL   r#   r   r3   r5   r2   r4   r6   r   )r.   whZpadwZpadhr/   r   r   r   
xywhn2xyxy  s         r   r   c                 C   s   |rt | || || f} | jd dks8J d| j t| tjrNt| n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. Defaults to 640
        h (int): The height of the image. Defaults to 640
        clip (bool): If True, the boxes will be clipped to the image boundaries. Defaults to False
        eps (float): The minimum value of the box's width and height. Defaults to 0.0

    Returns:
        y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height, normalized) format
    rL   r#   r   r3   r5   r2   r4   r6   )r9   rh   rB   r   rC   r   r&   )r.   r   r   r   Zepsr/   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
    r3   r5   r2   r4   r6   rB   r   rC   cloner&   copyr   r   r   r   	xywh2ltwh  s    
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.
    r5   r3   r6   r4   r   r   r   r   r   	xyxy2ltwh  s    
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.
    r3   r5   r2   r4   r6   r   r   r   r   r   	ltwh2xywh  s    
r   c           
   	   C   s   t | tj}|r|   n| }|t| dd}g }|D ]:}t|\\}}\}}}	|	|||||	d t
j g q:|rt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).
    rL   r2      r   r"   )rB   r   rC   cpunumpyreshaperM   r   ZminAreaRectappendr&   pirg   r   r"   Zasarray)
r.   Zis_torchZpointsrboxesZptsZcxcyr   r   angler   r   r   xyxyxyxy2xywhr  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).
    .Nr2   c                 3   s"   | ]} d ||d f V  qdS ).r1   Nr   r[   r   r.   r   r   	<genexpr>:  r`   z!xywhr2xyxyxyxy.<locals>.<genexpr>ra   rL   rc   )
rB   r   rC   cossinrj   stackr&   concatenaterl   )r.   r   r   rj   r   Zctrr   r   r   Z	cos_valueZ	sin_valueZvec1Zvec2Zpt1Zpt2Zpt3Zpt4r   r   r   xywhr2xyxyxyxy(  s     



r   c                 C   sJ   t | tjr|  nt| }| d | d  |d< | d | d  |d< |S )a  
    It converts the 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:
        y (np.ndarray | torch.Tensor): the xyxy coordinates of the bounding boxes.
    r5   r3   r6   r4   r   r   r   r   r   	ltwh2xyxyG  s    
r   c                 C   sH   g }| D ]0}|j \}}|| | | | g qtt|S )a.  
    It converts 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;   sr.   r/   r   r   r   segments2boxesW  s
    

$r     c                    s   t | D ]\} tj  ddddf fdd tdt d |tt tj fddtdD tjddd	j	| |< q| S )
ae  
    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. Defaults to 1000

    Returns:
        segments (list): the resampled segments.
    r   r1   N)Zaxisc              	      s&   g | ]}t  d d |f qS )N)r&   Zinterpr   r   r.   Zxpr   r   r_   x  r`   z%resample_segments.<locals>.<listcomp>r2   r!   rL   )
rk   r&   r   ZlinspacerM   arangerl   float32r   r$   )r   r   r   r   r   r   resample_segmentsh  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 )aV  
    It takes a mask and a bounding box, and returns a mask that is cropped to the bounding box.

    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): The masks are being cropped to the bounding box.
    Nr#   r1   r   )rh   r   chunkr   r   r"   )r   r;   _r   r   x1y1Z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|
|}
|rt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. Default is False.

    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.
    rL   Nr   r2   r7   r1   bilinearFmodeZalign_cornersr   )rh   rp   rq   r   r   Finterpolategt_)protosmasks_inbboxesrh   Zupsampler   mhmwZihiwr   Zwidth_ratioZheight_ratioZdownsampled_bboxesr   r   r   process_mask  s    
r   c                 C   sP   | j \}}}||  |d d||}t|d |d }t||}|dS )a  
    It takes the output of the mask head, and crops it after upsampling to the bounding boxes.

    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:
        masks (torch.Tensor): The returned masks with dimensions [h, w, n]
    rL   Nr   r   )rh   rp   rq   scale_masksr   r   )r   r   r   rh   r   r   r   r   r   r   r   process_mask_native  s
    
r   c                 C   s   | j dd \}}t||d  ||d  }||d |  ||d |  g}|rp|d  d  < |d  d  < |rt|d t|d fnd\}}t||d  t||d   }	}
| d||	||
f } tj| |ddd	} | S )
a  
    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.
    r2   Nr   r1   )r   r   .r   Fr   )rh   r(   rD   r   r   )r   rh   r>   r   r   r?   r@   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 }|r|d  |d 8  < |d  |d 8  < |d  |  < |d  |  < t||}|r|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]. Defaults to False.
        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   r1   r2   r3   r4   )r(   r   )r:   r   r<   r=   	normalizer>   r?   r@   r   r   r   scale_coords  s    "2
r   c                 C   st   | j dd\}}}}}t||k||}t||k||}t||k||tjd  tj }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.
    rL   rJ   r2   )Zunbindr   ro   rE   r   r   )r   r.   r/   r   r   r	   Zw_Zh_r   r   r   regularize_rboxes   s
    
"r   largestc                 C   s   g }|     dD ]}t|tjtjd }|r|dkrVt	dd |D }q|dkrt
|t
dd |D   dd	}n
td
}||d q|S )aC  
    It takes a list of masks(n,h,w) and returns a list of segments(n,xy).

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

    Returns:
        segments (List): list of segment masks
    uint8r   concatc                 S   s   g | ]}| d dqS )rL   r2   )r   r[   r.   r   r   r   r_   "  r`   z"masks2segments.<locals>.<listcomp>r   c                 S   s   g | ]}t |qS r   )rM   r   r   r   r   r_   $  r`   rL   r2   )r   r2   r   )rD   r   r   Zastyper   ZfindContoursZRETR_EXTERNALZCHAIN_APPROX_SIMPLEr&   r   r'   Zargmaxr   r*   r   )r   Zstrategyr   r.   r   r   r   r   masks2segments  s    ,
r   )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   r2   r7   r1      )Zpermute
contiguousr   tor   r   r   r   )r   r   r   r   convert_torch2numpy_batch+  s    
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_str8  s    
r   )r    r    )NTF)rH   )rT   rH   NFFr   rU   r   rV   rW   rX   TF)N)r    r    r   r   )r    r    Fr   )r   )F)T)NFT)r   )1
contextlibrE   r   r   r   r   r&   r   Ztorch.nn.functionalnnZ
functionalr   Zultralytics.utilsr   Zultralytics.utils.metricsr   ContextDecoratorr   r0   rA   rG   rS   r   r9   r   r   r   ri   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rC   Zndarrayr   r   r   r   r   r   <module>   sj   0

&
             
 
#



!

#
