o
    WhF                     @   s   d dl mZ d dlmZ d dlmZ d dlmZ d dlZ	ddl
mZmZmZmZmZmZmZ dd	 Zed
ZedZg dZdZG dd dZG dd dZdS )    )abc)repeat)Number)ListN   )	ltwh2xywh	ltwh2xyxyresample_segments	xywh2ltwh	xywh2xyxy	xyxy2ltwh	xyxy2xywhc                    s    fdd}|S )zFrom PyTorch internals.c                    s   t | tjr| S tt|  S )zDParse input to return n-tuple by repeating singleton values n times.)
isinstancer   Iterabletupler   )xn N/var/www/vscode/kcb/lib/python3.10/site-packages/ultralytics/utils/instance.pyparse   s   z_ntuple.<locals>.parser   )r   r   r   r   r   _ntuple   s   r         )xyxyxywhltwh)Bboxes	Instancesc                   @   sj   e Zd ZdZddddZdd Zd	d
 Zdd Zdd Zdd Z	e
dded  dd fddZdddZdS )r   a  
    A class for handling bounding boxes.

    The class supports various bounding box formats like 'xyxy', 'xywh', and 'ltwh'.
    Bounding box data should be provided in numpy arrays.

    Attributes:
        bboxes (np.ndarray): The bounding boxes stored in a 2D numpy array with shape (N, 4).
        format (str): The format of the bounding boxes ('xyxy', 'xywh', or 'ltwh').

    Note:
        This class does not handle normalization or denormalization of bounding boxes.
    r   returnNc                 C   sj   |t v sJ d| dt  |jdkr|dddf n|}|jdks$J |jd dks-J || _|| _dS )a  
        Initialize the Bboxes class with bounding box data in a specified format.

        Args:
            bboxes (np.ndarray): Array of bounding boxes with shape (N, 4) or (4,).
            format (str): Format of the bounding boxes, one of 'xyxy', 'xywh', or 'ltwh'.
        Invalid bounding box format: , format must be one of r   Nr   r   )_formatsndimshapebboxesformat)selfr%   r&   r   r   r   __init__1   s   
zBboxes.__init__c                 C   s   |t v sJ d| dt  | j|krdS | jdkr#|dkr tnt}n| jdkr1|dkr.tnt}n|dkr7tnt}|| j| _|| _dS )z
        Convert bounding box format from one type to another.

        Args:
            format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'.
        r    r!   Nr   r   )	r"   r&   r   r   r   r
   r   r   r%   )r'   r&   funcr   r   r   convertA   s   



zBboxes.convertc                 C   sv   | j dkr)| jdddf | jdddf  | jdddf | jdddf   S | jdddf | jdddf  S )zReturn box areas.r   Nr   r      r   )r&   r%   r'   r   r   r   areasT   s
   
F"zBboxes.areasc                 C   s   t |tr	t|}t |ttfsJ t|dksJ | jdddf  |d 9  < | jdddf  |d 9  < | jdddf  |d 9  < | jdddf  |d 9  < dS )z
        Multiply bounding box coordinates by scale factor(s).

        Args:
            scale (int | tuple | list): Scale factor(s) for four coordinates.
                If int, the same scale is applied to all coordinates.
        r   Nr   r   r   r+   r   r   	to_4tupler   listlenr%   )r'   scaler   r   r   mull      
"z
Bboxes.mulc                 C   s   t |tr	t|}t |ttfsJ t|dksJ | jdddf  |d 7  < | jdddf  |d 7  < | jdddf  |d 7  < | jdddf  |d 7  < dS )z
        Add offset to bounding box coordinates.

        Args:
            offset (int | tuple | list): Offset(s) for four coordinates.
                If int, the same offset is applied to all coordinates.
        r   Nr   r   r   r+   r.   )r'   offsetr   r   r   add}   r4   z
Bboxes.addc                 C   
   t | jS )zReturn the number of boxes.r1   r%   r,   r   r   r   __len__      
zBboxes.__len__r   
boxes_listc                 C   sj   t |ttfs	J |s| tdS tdd |D sJ t|dkr'|d S | tjdd |D |dS )a  
        Concatenate a list of Bboxes objects into a single Bboxes object.

        Args:
            boxes_list (List[Bboxes]): A list of Bboxes objects to concatenate.
            axis (int, optional): The axis along which to concatenate the bounding boxes.

        Returns:
            (Bboxes): A new Bboxes object containing the concatenated bounding boxes.

        Note:
            The input should be a list or tuple of Bboxes objects.
        r   c                 s       | ]}t |tV  qd S N)r   r   ).0boxr   r   r   	<genexpr>       z%Bboxes.concatenate.<locals>.<genexpr>r   c                 S      g | ]}|j qS r   r%   r>   br   r   r   
<listcomp>       z&Bboxes.concatenate.<locals>.<listcomp>axis)r   r0   r   npemptyallr1   concatenate)clsr;   rI   r   r   r   rM      s   zBboxes.concatenatec                 C   sL   t |trt| j| ddS | j| }|jdks"J d| dt|S )a  
        Retrieve a specific bounding box or a set of bounding boxes using indexing.

        Args:
            index (int | slice | np.ndarray): The index, slice, or boolean array to select
                                              the desired bounding boxes.

        Returns:
            (Bboxes): A new Bboxes object containing the selected bounding boxes.

        Raises:
            AssertionError: If the indexed bounding boxes do not form a 2-dimensional matrix.

        Note:
            When using boolean indexing, make sure to provide a boolean array with the same
            length as the number of bounding boxes.
        r   r   zIndexing on Bboxes with z failed to return a matrix!)r   intr   r%   reshaper#   )r'   indexrE   r   r   r   __getitem__   s
   

zBboxes.__getitem__)r   r   Nr   )r   r   )__name__
__module____qualname____doc__r(   r*   r-   r3   r6   r9   classmethodr   rM   rS   r   r   r   r   r   "   s    r   c                   @   s   e Zd ZdZd)d*ddZdd	 Zed
d Zd+ddZdd Z	dd Z
dd Zd,ddZdd Zdd Zdd Zdd Zd-dd Zd!d" Zed.d$ed  dd fd%d&Zed'd( ZdS )/r   a  
    Container for bounding boxes, segments, and keypoints of detected objects in an image.

    Attributes:
        _bboxes (Bboxes): Internal object for handling bounding box operations.
        keypoints (np.ndarray): Keypoints with shape (N, 17, 3) in format (x, y, visible).
        normalized (bool): Flag indicating whether the bounding box coordinates are normalized.
        segments (np.ndarray): Segments array with shape (N, M, 2) after resampling.

    Methods:
        convert_bbox: Convert bounding box format.
        scale: Scale coordinates by given factors.
        denormalize: Convert normalized coordinates to absolute coordinates.
        normalize: Convert absolute coordinates to normalized coordinates.
        add_padding: Add padding to coordinates.
        flipud: Flip coordinates vertically.
        fliplr: Flip coordinates horizontally.
        clip: Clip coordinates to stay within image boundaries.
        remove_zero_area_boxes: Remove boxes with zero area.
        update: Update instance variables.
        concatenate: Concatenate multiple Instances objects.

    Examples:
        >>> instances = Instances(
        ...     bboxes=np.array([[10, 10, 30, 30], [20, 20, 40, 40]]),
        ...     segments=[np.array([[5, 5], [10, 10]]), np.array([[15, 15], [20, 20]])],
        ...     keypoints=np.array([[[5, 5, 1], [10, 10, 1]], [[15, 15, 1], [20, 20, 1]]]),
        ... )
    Nr   Tr   c                 C   s$   t ||d| _|| _|| _|| _dS )a  
        Initialize the object with bounding boxes, segments, and keypoints.

        Args:
            bboxes (np.ndarray): Bounding boxes, shape (N, 4).
            segments (List | np.ndarray, optional): Segmentation masks.
            keypoints (np.ndarray, optional): Keypoints, shape (N, 17, 3) in format (x, y, visible).
            bbox_format (str, optional): Format of bboxes.
            normalized (bool, optional): Whether the coordinates are normalized.
        )r%   r&   N)r   _bboxes	keypoints
normalizedsegments)r'   r%   r^   r\   bbox_formatr]   r   r   r   r(      s   
zInstances.__init__c                 C   s   | j j|d dS )z
        Convert bounding box format.

        Args:
            format (str): Target format for conversion, one of 'xyxy', 'xywh', or 'ltwh'.
        r&   N)r[   r*   )r'   r&   r   r   r   convert_bbox   s   zInstances.convert_bboxc                 C   s
   | j  S )z%Calculate the area of bounding boxes.)r[   r-   r,   r   r   r   
bbox_areas   s   
zInstances.bbox_areasFc                 C   sx   | j j||||fd |rdS | jd  |9  < | jd  |9  < | jdur:| jd  |9  < | jd  |9  < dS dS )z
        Scale coordinates by given factors.

        Args:
            scale_w (float): Scale factor for width.
            scale_h (float): Scale factor for height.
            bbox_only (bool, optional): Whether to scale only bounding boxes.
        r2   N.r   .r   )r[   r3   r^   r\   )r'   scale_wscale_h	bbox_onlyr   r   r   r2      s   	
zInstances.scalec                 C   s|   | j sdS | jj||||fd | jd  |9  < | jd  |9  < | jdur9| jd  |9  < | jd  |9  < d| _ dS )z
        Convert normalized coordinates to absolute coordinates.

        Args:
            w (int): Image width.
            h (int): Image height.
        Nrc   rd   re   Fr]   r[   r3   r^   r\   r'   whr   r   r   denormalize  s   

zInstances.denormalizec                 C   s   | j rdS | jjd| d| d| d| fd | jd  |  < | jd  |  < | jdurA| jd  |  < | jd  |  < d| _ dS )z
        Convert absolute coordinates to normalized coordinates.

        Args:
            w (int): Image width.
            h (int): Image height.
        Nr   rc   rd   re   Tri   rj   r   r   r   	normalize$  s   &

zInstances.normalizec                 C   s~   | j rJ d| jj||||fd | jd  |7  < | jd  |7  < | jdur=| jd  |7  < | jd  |7  < dS dS )z
        Add padding to coordinates.

        Args:
            padw (int): Padding width.
            padh (int): Padding height.
        z1you should add padding with absolute coordinates.)r5   rd   re   N)r]   r[   r6   r^   r\   )r'   padwpadhr   r   r   add_padding6  s   
zInstances.add_paddingc                 C   sX   t | jr
| j| n| j}| jdur| j| nd}| j| }| jj}t||||| jdS )a  
        Retrieve a specific instance or a set of instances using indexing.

        Args:
            index (int | slice | np.ndarray): The index, slice, or boolean array to select the desired instances.

        Returns:
            (Instances): A new Instances object containing the selected boxes, segments, and keypoints if present.

        Note:
            When using boolean indexing, make sure to provide a boolean array with the same
            length as the number of instances.
        N)r%   r^   r\   r_   r]   )r1   r^   r\   r%   r[   r&   r   r]   )r'   rR   r^   r\   r%   r_   r   r   r   rS   F  s   
zInstances.__getitem__c                 C      | j jdkr3| jdddf  }| jdddf  }|| | jdddf< || | jdddf< n|| jdddf  | jdddf< || jd  | jd< | jdur`|| jd  | jd< dS dS )z`
        Flip coordinates vertically.

        Args:
            h (int): Image height.
        r   Nr   r+   re   r[   r&   r%   copyr^   r\   )r'   rl   y1y2r   r   r   flipud`     $
zInstances.flipudc                 C   rr   )za
        Flip coordinates horizontally.

        Args:
            w (int): Image width.
        r   Nr   r   rd   rs   )r'   rk   x1x2r   r   r   fliplrr  rx   zInstances.fliplrc                 C   s  | j j}| jdd | jddddgf d|| jddddgf< | jddddgf d|| jddddgf< |dkrD| j|d | jd d|| jd< | jd	 d|| jd	< | jdurd
| jd | jd dk | jd |kB | jd	 dk B | jd	 |kB < dS dS )z
        Clip coordinates to stay within image boundaries.

        Args:
            w (int): Image width.
            h (int): Image height.
        r   r`   Nr   r   r   r+   rd   re   g        ).r   )r[   r&   ra   r%   clipr^   r\   )r'   rk   rl   
ori_formatr   r   r   r|     s(   00
zInstances.clipc                 C   sN   | j dk}t|s%| j| | _t| jr| j| | _| jdur%| j| | _|S )z
        Remove zero-area boxes, i.e. after clipping some boxes may have zero width or height.

        Returns:
            (np.ndarray): Boolean array indicating which boxes were kept.
        r   N)rb   rL   r[   r1   r^   r\   )r'   goodr   r   r   remove_zero_area_boxes  s   


z Instances.remove_zero_area_boxesc                 C   s6   t || jjd| _|dur|| _|dur|| _dS dS )z
        Update instance variables.

        Args:
            bboxes (np.ndarray): New bounding boxes.
            segments (np.ndarray, optional): New segments.
            keypoints (np.ndarray, optional): New keypoints.
        r`   N)r   r[   r&   r^   r\   )r'   r%   r^   r\   r   r   r   update  s   	
zInstances.updatec                 C   r7   )z'Return the length of the instance list.r8   r,   r   r   r   r9     r:   zInstances.__len__r   instances_listc           
         s  t |ttfs	J |s| tdS tdd |D sJ t|dkr'|d S |d jdu}|d jj	}|d j
}tjdd |D |d}d	d |D }tt|dkrgt| tj fd
d|D |d}ntjdd |D |d}|rtjdd |D |dnd}	| |||	||S )a  
        Concatenate a list of Instances objects into a single Instances object.

        Args:
            instances_list (List[Instances]): A list of Instances objects to concatenate.
            axis (int, optional): The axis along which the arrays will be concatenated.

        Returns:
            (Instances): A new Instances object containing the concatenated bounding boxes,
                       segments, and keypoints if present.

        Note:
            The `Instances` objects in the list should have the same properties, such as
            the format of the bounding boxes, whether keypoints are present, and if the
            coordinates are normalized.
        r   c                 s   r<   r=   )r   r   )r>   instancer   r   r   r@     rA   z(Instances.concatenate.<locals>.<genexpr>r   Nc                 S   rB   r   rC   )r>   insr   r   r   rF     rG   z)Instances.concatenate.<locals>.<listcomp>rH   c                 S   s   g | ]}|j jd  qS )r   )r^   r$   rD   r   r   r   rF     s    c                    s<   g | ]}t |jrtt|j n
tjd  dftjdqS )r   r   )dtype)r1   r^   r	   r0   rJ   zerosfloat32rD   max_lenr   r   rF     s    c                 S   rB   r   )r^   rD   r   r   r   rF     rG   c                 S   rB   r   )r\   rD   r   r   r   rF     rG   )r   r0   r   rJ   rK   rL   r1   r\   r[   r&   r]   rM   	frozensetmax)
rN   r   rI   use_keypointr_   r]   	cat_boxesseg_lencat_segmentscat_keypointsr   r   r   rM     s,   


 zInstances.concatenatec                 C   s   | j jS )zReturn bounding boxes.)r[   r%   r,   r   r   r   r%     s   zInstances.bboxes)NNr   TrT   )F)r   r   )NNrU   )rV   rW   rX   rY   r(   ra   propertyrb   r2   rm   rn   rq   rS   rw   r{   r|   r   r   r9   rZ   r   rM   r%   r   r   r   r   r      s*    	



/r   )collectionsr   	itertoolsr   numbersr   typingr   numpyrJ   opsr   r   r	   r
   r   r   r   r   	to_2tupler/   r"   __all__r   r   r   r   r   r   <module>   s   $
 "