
    FPh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Zd dlm	c m
Z d dlZd dlmZ  G d de j                        Zd#dZd$dZd Z	 	 	 	 	 	 	 	 	 	 	 d%dZd	 Zd
 Zd&dZd Zd Zd'dZd(dZd Zd Zd Zd Zd Z d Z!d Z"d)dZ#d Z$d Z%d*dZ&d Z'd+dZ(d,dZ)d-dZ*dejV                  d ejX                  fd!Z-d" Z.y).    N)LOGGERc                   0    e Zd ZdZddZd Zd Zd Zd Zy)	Profilea\  
    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() as dt:
            pass  # slow operation here

        print(dt)  # prints "Elapsed time is 9.5367431640625e-07 s"
        ```
    c                 X    || _         t        j                  j                         | _        y)zt
        Initialize the Profile class.

        Args:
            t (float): Initial time. Defaults to 0.0.
        N)ttorchcudais_available)selfr   s     `C:\Users\daisl\Desktop\realtime-object-detection\venv\Lib\site-packages\ultralytics/utils/ops.py__init__zProfile.__init__    s     JJ++-	    c                 0    | j                         | _        | S )zStart timing.)timestartr   s    r   	__enter__zProfile.__enter__*   s    YY[
r   c                     | j                         | j                  z
  | _        | xj                  | j                  z  c_        y)zStop timing.N)r   r   dtr   )r   typevalue	tracebacks       r   __exit__zProfile.__exit__/   s*    ))+

*$''r   c                 "    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   s    r   __str__zProfile.__str__4   s    !$&&,,r   c                 ~    | j                   rt        j                   j                          t        j                         S )zGet current time.)r	   r   synchronizer   r   s    r   r   zProfile.time8   s%    99JJ""$yy{r   N)        )	__name__
__module____qualname____doc__r   r   r   r   r    r   r   r   r      s     .

-r   r   c                 t   | j                   \  }}|dk\  |dk\  z  ||k  z  ||k  z  }||   ||   }}t        |      r]t        j                  |j	                         |j	                         |j                         |j                         g| j                        S t        j                  d| j                        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yinsides         r   segment2boxr5   ?   s     99DAq1fa AJ/1;?FfIqyqARUVWRX288QUUWaeegquuw8N  ^`^f^f	_   r   c                 d   |Yt        | d   |d   z  | d   |d   z        }t        | d   |d   |z  z
  dz  dz
        t        | d   |d   |z  z
  dz  dz
        f}n|d   d   }|d   }|r(|dddgfxx   |d   z  cc<   |dddgfxx   |d   z  cc<   |dddfxx   |z  cc<   t        ||       |S )	a  
    Rescales bounding boxes (in the format of xyxy) 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.

    Returns:
        boxes (torch.Tensor): The scaled bounding boxes, in the format of (x1, y1, x2, y2)
    Nr         g?.   r'   )r,   round
clip_boxes)
img1_shapeboxes
img0_shape	ratio_padpaddinggainpads          r   scale_boxesrC   S   s    " :a=:a=0*Q-*Q-2OPZ]Z]T%99Q>DEu]Z]T11Q6<H> > |AlcAq6kc!f$cAq6kc!f$	#rr'NdNuj!Lr   c                     t        |t        j                        rt        |j	                               }t        j                  | |z        |z  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   divisors     r   make_divisiblerK   t   s:     '5<<(gkkm$99Q[!G++r   c                     d|cxk  rdk  sn J d| d       d|cxk  rdk  sn J d| d       t        | t        t        f      r| d   } | j                  }d|j                  v }|r| j                         } | j                  d   }|xs | j                  d   dz
  }| j                  d   |z
  dz
  }d|z   }| ddd|f   j                  d      |kD  }d	|	|z  z   }||dkD  z  }| j                  d
d      } t        | dddf         | dddf<   t        j                         }t        j                  dd|z   f| j                        g|z  }t        |       D ]  \  }}|||      }|rt        ||         r||   }t        j                  t        |      ||z   dz   f|j                        }t        |ddddf         |ddddf<   d|t        t        |            |dddf   j!                         dz   f<   t        j"                  ||fd      }|j                  d   s|j%                  d||fd      \  }}}|rZt        j&                  ||kD        \  }}t        j"                  ||   ||d|z   df   |dddf   j)                         ||   fd      }nS|j+                  dd      \  }}t        j"                  |||j)                         |fd      |j-                  d
      |kD     }|?||ddddf   t        j.                  ||j                        k(  j1                  d         }|j                  d   }|s||
kD  r||dddf   j3                  d      d|
    }|ddddf   |rdn|z  } |ddddf   | z   |dddf   }"}!t4        j6                  j9                  |!|"|      }|d| }||   ||<   |r||   j;                  |      ||<   t        j                         |z
  |kD  st=        j>                  d|dd        |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, 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

    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   r7   zInvalid Confidence threshold z&, valid values are between 0.0 and 1.0zInvalid IoU mpsr'   N      ?.   )device   g      ?T)keepdim)
descendingu   WARNING ⚠️ NMS time limit z.3fz
s exceeded) rE   listtuplerR   r   cpushapeamax	transpose	xywh2xyxyr   r   r.   	enumeratelenrangelongcatsplitwherefloatr-   viewtensorr)   argsorttorchvisionopsnmstor   warning)#
prediction
conf_thres	iou_thresclassesagnosticmulti_labellabelsmax_detncmax_time_imgmax_nmsmax_whrR   rM   bsnmmixc
time_limitr   outputxir2   lbvboxclsmaskijconfncr=   scoress#                                      r   non_max_suppressionr      sO   Z 
as#@Lr!ss	Q`,yk9_ ``*tUm,]
F
6;;
C
^^%
			!	B		(
  #a'B			!	r	!A	%B	
RB	AqtG		!	!!	$z	1B |b((J26K%%b"-J#JsBQBw$78JsBQBw		Akk1a"f+j.?.?@ABFF:&A bfI c&*oBSWb2gk2188DA AqsF,Aa!eH58AeCGnbAhmmo112		1a&!$A wwqz !Ra0S$;;sZ/0DAq		3q61QAt^#4a4j6F6F6H$q'RTUVAggag.GD!		3aggi6:499R=:;UVA 1Q!V9WQXX FFKKANOA GGAJw;!AqD'//T/28G<=A a1fIhF3!RaR%1a1gvOOvy9hwK qTr
v.F2JIIK!Oz)NN;Js;K:VWM '~ Mr   c                    t        | t        j                        ra| d   j                  d|d          | d   j                  d|d          | d   j                  d|d          | d   j                  d|d          y
| dddgf   j	                  d|d         | dddgf<   | ddd	gf   j	                  d|d         | ddd	gf<   y
)z
    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
    .r   r   r7   .r7   .r8   .r9   .r8   r9   NrE   r   rF   clamp_clip)r=   rY   s     r   r;   r;     s     %&fQa)fQa)fQa)fQa)"3A;/44QaAcAq6k"3A;/44QaAcAq6kr   c                    t        | t        j                        r1| d   j                  d|d          | d   j                  d|d          y| d   j	                  d|d         | d<   | d   j	                  d|d         | d<   y)a  
    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:
        (None): The function modifies the input `coordinates` in place, by clipping each coordinate to the image boundaries.
    r   r   r7   r   Nr   )coordsrY   s     r   clip_coordsr     s~     &%,,'vaq*vaq*,,Qa9v,,Qa9vr   c                 l   | j                   }|dd |dd k(  r| S |At        |d   |d   z  |d   |d   z        }|d   |d   |z  z
  dz  |d   |d   |z  z
  dz  f}n|d   d   }|d   }t        |d         t        |d         }}t        |d   |d   z
        t        |d   |d   z
        }	}t        | j                         dk  r!t	        dt        | j                                | ||||	f   } t        j                  | |d   |d   f      } t        | j                         dk(  r| dddddf   } | S )ao  
    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 (torch.Tensor): The masks that are being returned.
    Nr8   r   r7   z/"len of masks shape" should be 2 or 3, but got )rY   r,   rG   r^   
ValueErrorcv2resize)
masks	im0_shaper?   	im1_shaperA   rB   topleftbottomrights
             r   scale_imager   1  sq    I!}	"1%9Q<)A,.	!y|0KL|ilT11Q61	RSW[H[9[_`8``|AlCFSQ[C	!s1v-.IaL3q64I0JEF
5;;!J3u{{K[J\]^^#f*d5j()EJJuy|Yq\:;E
5;;1aDj!Lr   c                 V   | j                   d   dk(  sJ d| j                           t        | t        j                        rt        j                  |       nt        j                  |       }| d   | d   z   dz  |d<   | d   | d   z   dz  |d<   | d   | d   z
  |d<   | d   | d   z
  |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.
    rO   r'   9input shape last dimension expected 4 but input shape is r   r   r8   r   r   rY   rE   r   rF   
empty_liker*   r2   r3   s     r   	xyxy2xywhr   T  s     772;!bXYZY`Y`Xabb)!U\\:a@PA6QvY&!+AfI6QvY&!+AfI&	AfI%AfI&	AfI%AfIHr   c                 R   | j                   d   dk(  sJ d| j                           t        | t        j                        rt        j                  |       nt        j                  |       }| d   dz  }| d   dz  }| d   |z
  |d<   | d   |z
  |d<   | d   |z   |d<   | d   |z   |d<   |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.

    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.
    rO   r'   r   r   r8   r   r   r   r   )r2   r3   dwdhs       r   r\   r\   h  s     772;!bXYZY`Y`Xabb)!U\\:a@PA	
6QB	
6QB&	BAfI&	BAfI&	BAfI&	BAfIHr   c                    | j                   d   dk(  sJ d| j                           t        | t        j                        rt        j                  |       nt        j                  |       }|| d   | d   dz  z
  z  |z   |d<   || d   | d   dz  z
  z  |z   |d<   || d   | d   dz  z   z  |z   |d<   || d   | d   dz  z   z  |z   |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.
    rO   r'   r   r   r   r8   r   r   r   )r2   whpadwpadhr3   s         r   
xywhn2xyxyr   ~  s     772;!bXYZY`Y`Xabb)!U\\:a@PAQvY6Q./$6AfIQvY6Q./$6AfIQvY6Q./$6AfIQvY6Q./$6AfIHr   c                    |rt        | ||z
  ||z
  f       | j                  d   dk(  sJ d| j                          t        | t        j                        rt        j
                  |       nt        j
                  |       }| d   | d   z   dz  |z  |d<   | d   | d   z   dz  |z  |d<   | d   | d   z
  |z  |d<   | d   | d   z
  |z  |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
    rO   r'   r   r   r   r8   r   r   )r;   rY   rE   r   rF   r   r*   )r2   r   r   r   epsr3   s         r   
xyxy2xywhnr     s     1q3wC()772;!bXYZY`Y`Xabb)!U\\:a@PAF)ai'1,1AfIF)ai'1,1AfI6QvY&!+AfI6QvY&!+AfIHr   c                     t        | t        j                        r| j                         nt	        j
                  |       }| d   | d   dz  z
  |d<   | d   | d   dz  z
  |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
    r   r   r8   r   r   rE   r   rF   cloner*   copyr   s     r   	xywh2ltwhr     _      5<<0	bggajA&	AfIM)AfI&	AfIM)AfIHr   c                     t        | t        j                        r| j                         nt	        j
                  |       }| d   | d   z
  |d<   | d   | d   z
  |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   r   r   r   r   r   s     r   	xyxy2ltwhr     W      5<<0	bggajA&	AfI%AfI&	AfI%AfIHr   c                     t        | t        j                        r| j                         nt	        j
                  |       }| d   | d   dz  z   |d<   | d   | d   dz  z   |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.
    r   r   r8   r   r   r   r   s     r   	ltwh2xywhr     r   r   c                 2   t        | t        j                        }|r t        j                  t        j                  fnt
        j                  t
        j                  f\  }}| j                  \  }}}}}}	}
}||z   dz  }||	z   dz  }||z
  }||z
  } ||dz  |dz  z         } |||z
  dz  ||	z
  dz  z         } || |      }|dt        j                  z  z  }|r$t        j                  |||||f      j                  S t        j                  |||||fd      S )a9  
    Convert batched Oriented Bounding Boxes (OBB) from [xy1, xy2, xy3, xy4] to [xywh, rotation].

    Args:
        corners (numpy.ndarray | torch.Tensor): Input corners of shape (n, 8).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted data in [cx, cy, w, h, rotation] format of shape (n, 5).
    r8        f@r7   dim)rE   r*   ndarrayarctan2sqrtr   atan2r(   rH   pivstackstack)cornersis_numpyr   r   x1y1x2y2x3y3x4y4cxcydx21dy21r   r   rotations                      r   xyxyxyxy2xywhrr     s    '2::.H+32::rww'%++uzz9RKE4%,YY"BBBB
r'QB
r'QB7D7DTQY"#Ab2g!^rBw1n,-AdUD!HH4<299b"aH-.00n%++rSUWXZ[]eNflmBnnr   c           
      |   t        | t        j                        }|r t        j                  t        j                  fnt
        j                  t
        j                  f\  }}| j                  \  }}}}}|t        j                  dz  z  }|dz  }	|dz  }
 ||      } ||      }|	|z  }|	|z  }|
|z  }|
|z  }||z
  |z
  }||z   |z
  }||z   |z
  }||z
  |z
  }||z   |z   }||z
  |z   }||z
  |z   }||z   |z   }|r't        j                  ||||||||f      j                  S t        j                  ||||||||fd      S )a>  
    Convert batched Oriented Bounding Boxes (OBB) from [xywh, rotation] to [xy1, xy2, xy3, xy4].

    Args:
        center (numpy.ndarray | torch.Tensor): Input data in [cx, cy, w, h, rotation] format of shape (n, 5).

    Returns:
        (numpy.ndarray | torch.Tensor): Converted corner points of shape (n, 8).
    r   r8   r7   r   )rE   r*   r   cossinr   r(   rH   r   r   r   )centerr   r   r   r   r   r   r   r   dxdycos_rotsin_rot
dx_cos_rot
dx_sin_rot
dy_cos_rot
dy_sin_rotr   r   r   r   r   r   r   r   s                            r   xywhr2xyxyxyxyr     sj    &"**-H#+%))UYY1GHC#XXBAq(%H	
QB	
QB(mG(mGgJgJgJgJ	j:	%B	j:	%B	j:	%B	j:	%B	j:	%B	j:	%B	j:	%B	j:	%B<D299b"b"b"b"5688 1%++	RRRR(aK1 1r   c                     t        | t        j                        r| j                         nt	        j
                  |       }| d   | d   z   |d<   | d   | d   z   |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.
    r   r   r   r   r   r   s     r   	ltwh2xyxyr   "  r   r   c                    g }| D ]^  }|j                   \  }}|j                  |j                         |j                         |j                         |j                         g       ` t	        t        j                  |            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(   appendr,   r-   r   r*   r+   )segmentsr=   sr2   r3   s        r   segments2boxesr   2  sb     Ess1aeegquuw9:  RXXe_%%r   c                    t        |       D ]  \  }}t        j                  ||ddddf   fd      }t        j                  dt	        |      dz
  |      }t        j
                  t	        |            }t        j                  t        d      D cg c]   }t        j                  |||dd|f         " c}t        j                        j                  dd      j                  | <    | S c c}w )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   r7   N)axisr8   r%   rO   )r]   r*   concatenatelinspacer^   aranger_   interpfloat32reshaper(   )r   r   r   r   r2   xps         r   resample_segmentsr   C  s     (#1NNAq1ay>2KK3q6A:q)YYs1vnnq%RAbii2qAw&?%R+-::77>wq"~aa 		 $ O &Ss   %C.
c                 r   | j                   \  }}}t        j                  |dddddf   dd      \  }}}}t        j                  || j                  |j
                        ddddf   }	t        j                  || j                  |j
                        ddddf   }
| |	|k\  |	|k  z  |
|k\  z  |
|k  z  z  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'   r7   )rR   r&   )rY   r   chunkr   rR   r&   )r   r=   r   r   r   r   r   r   r   rr   s              r   	crop_maskr   W  s     kkGAq![[q!Tz!2Aq9NBBQu||288<T4]KAQu||288<T1d]KAQ"WR(AG4B?@@r   c                    | j                   \  }}}|| j                         j                  |d      z  j                         j                  d||      }t	        j
                  |d   |dd      d   }t        ||      }|j                  d      S )a  
    Takes the output of the mask head, and applies the mask to the bounding boxes. This produces masks of higher quality
    but is slower.

    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 upsampled masks.
    rO   NbilinearFmodealign_cornersr   rN   )rY   rd   re   sigmoidFinterpolater   gt_protosmasks_inbboxesrY   r   mhmwr   s           r   process_mask_upsampler  j  s     IAr2++Ar22;;=BB2r2NEMM%+u:USTUVEeV$E99S>r   c                    | j                   \  }}}|\  }}	|| j                         j                  |d      z  j                         j                  d||      }
|j	                         }|dddfxx   ||	z  z  cc<   |dddfxx   ||	z  z  cc<   |dddfxx   ||z  z  cc<   |dddfxx   ||z  z  cc<   t        |
|      }
|rt        j                  |
d   |dd	      d   }
|
j                  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.
    rO   Nr   r8   r9   r7   r   Fr   rN   )	rY   rd   re   r  r   r   r  r  r  )r  r  r	  rY   upsampler   r
  r  ihiwr   downsampled_bboxess               r   process_maskr    s      IAr2FB++Ar22;;=BB2r2NEq!tR'q!tR'q!tR'q!tR'e/0EeDk5zQVWXYZ99S>r   c                    | j                   \  }}}|| j                         j                  |d      z  j                         j                  d||      }t	        |d   |      d   }t        ||      }|j                  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]
    rO   Nr   rN   )rY   rd   re   r  scale_masksr   r  r  s           r   process_mask_nativer    sw     IAr2++Ar22;;=BB2r2NEdU+A.EeV$E99S>r   c                    | j                   dd \  }}t        ||d   z  ||d   z        }||d   |z  z
  ||d   |z  z
  g}|r|dxx   dz  cc<   |dxx   dz  cc<   |rt        |d         t        |d         fnd\  }}t        ||d   z
        t        ||d   z
        }
}	| d||	||
f   } t        j                  | |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.
    r8   Nr   r7   )r   r   .r   Fr   )rY   r,   rG   r  r  )r   rY   r@   r
  r  rA   rB   r   r   r   r   s              r   r  r    s     [[_FBrE!H}b58m,Da4eAho!5
6CA!A!.5SVc#a&k*6ICc!f%s2A;'7EF#s6z4:-.EMM%ZuMELr   c                 z   |At        | d   |d   z  | d   |d   z        }| d   |d   |z  z
  dz  | d   |d   |z  z
  dz  f}n|d   d   }|d   }|r |dxx   |d   z  cc<   |dxx   |d   z  cc<   |dxx   |z  cc<   |dxx   |z  cc<   t        ||       |r |dxx   |d   z  cc<   |dxx   |d   z  cc<   |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.
    r   r7   r8   r   r   )r,   r   )r<   r   r>   r?   	normalizer@   rA   rB   s           r   scale_coordsr    s      :a=:a=0*Q-*Q-2OP!}z!}t33q8:a=:VW=[_K_;_cd:dd|Alv#a& v#a& 
6NdN
6NdN
#v*Q-'v*Q-'Mr   c                    g }| j                         j                         j                         j                  d      D ]  }t	        j
                  |t        j                  t        j                        d   }|r|dk(  r4t        j                  |D cg c]  }|j                  dd       c}      }n{|dk(  rvt        j                  |t        j                  |D cg c]  }t        |       c}      j                                  j                  dd      }nt        j                  d      }|j                  |j                  d              |S c c}w c c}w )	aB  
    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   concatrO   r8   largest)r   r8   r   )rG   rX   numpyastyper   findContoursRETR_EXTERNALCHAIN_APPROX_SIMPLEr*   r   r   r+   r^   argmaxr.   r   )r   strategyr   r2   r   s        r   masks2segmentsr%    s    HYY[__$$&--g6Q 1 133J3JKAN8#NNa#@aAIIb!$4a#@AY&HHQrxx(;AQ(;<CCEFGOOPRTUV A+, 7 O $A(;s   E
Ebatchreturnc                     | j                  dddd      j                         dz  j                  dd      j                  t        j
                        j                         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   r8   r9   r7      )permute
contiguousclamprk   r   r  rX   r  )r&  s    r   convert_torch2numpy_batchr-    sU     MM!Q1%002S8??3GJJ5;;W[[]cceer   c                 2    t        j                  dd|       S )z
    Cleans a string by replacing special characters with underscore _

    Args:
        s (str): a string needing special characters replaced

    Returns:
        (str): a string with special characters replaced by an underscore _
    u"   [|@#!¡·$€%&()=?¿^*;:,¨´><+]_)patternreplstring)resub)r   s    r   	clean_strr5    s     66>SQRSSr   )  r6  )NT)g      ?g?NFFr#   i,  r   g?i0u  i   )N)r6  r6  r   r   )r6  r6  Fr   )i  )F)T)NFT)r  )/
contextlibrH   r3  r   r   r  r*   r   torch.nn.functionalnn
functionalr  rh   ultralytics.utilsr   ContextDecoratorr   r5   rC   rK   r   r;   r   r   r   r\   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r%  rF   r   r-  r5  r#   r   r   <module>r=     s     	  
      $+j)) +\ (B,$ EPB$:& F(,.4   o8$1N &"(A&*@(0 F2
fU\\ 
fbjj 
f
Tr   