U
    hNZ                  	   @  sr  d dl mZ d dlmZmZmZ d dlZd dlm	Z	 ddl
mZmZ ddd	d
dddddg	ZdZG dd deZG dd deZe	ddddddZe	ddddddZddddddZe	d4dddddddd	Ze	d5ddddddd d
Ze	dd!d"d#dZe	ddddd$d%Zd6ddd(d(d(d(dd)d*dZdd(d+d,d-dZddd.d/d0Zdddd1d2d3ZdS )7    )annotations)AnyLiteralSequenceN)handle_empty_array   )DataProcessorParamsnormalize_bboxesdenormalize_bboxes convert_bboxes_to_albumentations"convert_bboxes_from_albumentationscheck_bboxesfilter_bboxesunion_of_bboxesBboxProcessor
BboxParams   c                
      sz   e Zd ZdZdddddddd	d	d
 fddZdd fddZed	dddZeddddZddddZ	  Z
S )r   a'  Parameters of bounding boxes

    Args:
        format Literal["coco", "pascal_voc", "albumentations", "yolo"]: format of bounding boxes.

            The `coco` format
                `[x_min, y_min, width, height]`, e.g. [97, 12, 150, 200].
            The `pascal_voc` format
                `[x_min, y_min, x_max, y_max]`, e.g. [97, 12, 247, 212].
            The `albumentations` format
                is like `pascal_voc`, but normalized,
                in other words: `[x_min, y_min, x_max, y_max]`, e.g. [0.2, 0.3, 0.4, 0.5].
            The `yolo` format
                `[x, y, width, height]`, e.g. [0.1, 0.2, 0.3, 0.4];
                `x`, `y` - normalized bbox center; `width`, `height` - normalized bbox width and height.

        label_fields (list): List of fields joined with boxes, e.g., labels.
        min_area (float): Minimum area of a bounding box in pixels or normalized units.
            Bounding boxes with an area less than this value will be removed. Default: 0.0.
        min_visibility (float): Minimum fraction of area for a bounding box to remain in the list.
            Bounding boxes with a visible area less than this fraction will be removed. Default: 0.0.
        min_width (float): Minimum width of a bounding box in pixels or normalized units.
            Bounding boxes with a width less than this value will be removed. Default: 0.0.
        min_height (float): Minimum height of a bounding box in pixels or normalized units.
            Bounding boxes with a height less than this value will be removed. Default: 0.0.
        check_each_transform (bool): If True, bounding boxes will be checked after each dual transform. Default: True.
        clip (bool): If True, bounding boxes will be clipped to the image borders before applying any transform.
            Default: False.

    N        TFz9Literal[('coco', 'pascal_voc', 'albumentations', 'yolo')]zSequence[Any] | Nonefloatboolformatlabel_fieldsmin_areamin_visibility	min_width
min_heightcheck_each_transformclipc	           	        s6   t  || || _|| _|| _|| _|| _|| _d S N)super__init__r   r   r   r   r   r   )	selfr   r   r   r   r   r   r   r   	__class__ B/tmp/pip-unpacked-wheel-e8onvpoz/albumentations/core/bbox_utils.pyr"   :   s    zBboxParams.__init__dict[str, Any]returnc              	     s2   t   }|| j| j| j| j| j| jd |S )N)r   r   r   r   r   r   )	r!   to_dict_privateupdater   r   r   r   r   r   )r#   datar$   r&   r'   r+   M   s    

zBboxParams.to_dict_privatec                 C  s   dS )NTr&   clsr&   r&   r'   is_serializable[   s    zBboxParams.is_serializablestrc                 C  s   dS )Nr   r&   r.   r&   r&   r'   get_class_fullname_   s    zBboxParams.get_class_fullnamec                 C  sF   d| j  d| j d| j d| j d| j d| j d| j d| j d	S )
NzBboxParams(format=z, label_fields=z, min_area=z, min_visibility=z, min_width=z, min_height=z, check_each_transform=z, clip=)r   r#   r&   r&   r'   __repr__c   s    DzBboxParams.__repr__)Nr   r   r   r   TF)__name__
__module____qualname____doc__r"   r+   classmethodr0   r2   r5   __classcell__r&   r&   r$   r'   r      s   "       "c                      s   e Zd Zdddd fddZeddd	d
ZdddddZddddddZddddddZddddddZ	ddddddZ
  ZS )r   Nr   zdict[str, str] | None)paramsadditional_targetsc                   s   t  || d S r    )r!   r"   )r#   r<   r=   r$   r&   r'   r"   l   s    zBboxProcessor.__init__r1   r)   c                 C  s   dS )Nbboxesr&   r4   r&   r&   r'   default_data_nameo   s    zBboxProcessor.default_data_namer(   None)r-   r*   c                   s   | j D ]H}| kot | }|rt | d tk r| jjd krd}t|q| jjr~t fdd| jjD s~d}t|d S )Nr   zoPlease specify 'label_fields' in 'bbox_params' or add labels to the end of bbox because bboxes must have labelsc                 3  s   | ]}| kV  qd S r    r&   ).0ir-   r&   r'   	<genexpr>|   s     z2BboxProcessor.ensure_data_valid.<locals>.<genexpr>zOYour 'label_fields' are not valid - them must have same names as params in dict)Zdata_fieldslenBBOX_WITH_LABEL_SHAPEr<   r   
ValueErrorall)r#   r-   Z	data_nameZdata_existsmsgr&   rC   r'   ensure_data_valids   s    
$
"zBboxProcessor.ensure_data_valid
np.ndarraytuple[int, int])r-   image_shaper*   c                 C  s(   |  t ||| jj| jj| jj| jjdS )Nr   r   r   r   )r   r<   r   r   r   r   r#   r-   rM   r&   r&   r'   filter   s    zBboxProcessor.filterc                 C  s   t | d S r    )r   rO   r&   r&   r'   check   s    zBboxProcessor.checkc                 C  s    t jt|| jj|ddt jdS )NTcheck_validityZdtype)nparrayr   r<   r   float32rO   r&   r&   r'   convert_from_albumentations   s    z)BboxProcessor.convert_from_albumentationsc                 C  sP   | j jr<t|| j j|dd}t||ddddd}t| |S t|| j j|ddS )NFrR   r   rN   T)r<   r   r   r   r   r   )r#   r-   rM   Zdata_npr&   r&   r'   convert_to_albumentations   s    z'BboxProcessor.convert_to_albumentations)N)r6   r7   r8   r"   propertyr?   rJ   rP   rQ   rX   rY   r;   r&   r&   r$   r'   r   k   s   rK   rL   )r>   rM   r*   c                 C  sZ   |dd \}}|   t}|ddddgf  |  < |ddddgf  |  < |S )a  Normalize array of bounding boxes.

    Args:
        bboxes: Denormalized bounding boxes `[(x_min, y_min, x_max, y_max, ...)]`.
        image_shape: Image shape `(height, width)`.

    Returns:
        Normalized bounding boxes `[(x_min, y_min, x_max, y_max, ...)]`.

    N   r   r      copyastyper   )r>   rM   rowscols
normalizedr&   r&   r'   r
      s
    c                 C  sZ   |dd \}}|   t}|ddddgf  |9  < |ddddgf  |9  < |S )a  Denormalize  array of bounding boxes.

    Args:
        bboxes: Normalized bounding boxes `[(x_min, y_min, x_max, y_max, ...)]`.
        image_shape: Image shape `(height, width)`.

    Returns:
        Denormalized bounding boxes `[(x_min, y_min, x_max, y_max, ...)]`.

    Nr[   r   r   r\   r]   )r>   rM   r`   ra   Zdenormalizedr&   r&   r'   r      s
    c                 C  s   t | dkrtjg tjdS |\}}|  }|ddddgf  |9  < |ddddgf  |9  < |dddf |dddf  |dddf |dddf   S )a  Calculate areas for multiple bounding boxes.

    This function computes the areas of bounding boxes given their normalized coordinates
    and the dimensions of the image they belong to. The bounding boxes are expected to be
    in the format [x_min, y_min, x_max, y_max] with normalized coordinates (0 to 1).

    Args:
        bboxes (np.ndarray): A numpy array of shape (N, 4+) where N is the number of bounding boxes.
                             Each row contains [x_min, y_min, x_max, y_max] in normalized coordinates.
                             Additional columns beyond the first 4 are ignored.
        image_shape (tuple[int, int]): A tuple containing the height and width of the image (height, width).

    Returns:
        np.ndarray: A 1D numpy array of shape (N,) containing the areas of the bounding boxes in pixels.
                    Returns an empty array if the input `bboxes` is empty.

    Note:
        - The function assumes that the input bounding boxes are valid (i.e., x_max > x_min and y_max > y_min).
          Invalid bounding boxes may result in negative areas.
        - The function preserves the input array and creates a copy for internal calculations.
        - The returned areas are in pixel units, not normalized.

    Example:
        >>> bboxes = np.array([[0.1, 0.1, 0.5, 0.5], [0.2, 0.2, 0.8, 0.8]])
        >>> image_shape = (100, 100)
        >>> areas = calculate_bbox_areas(bboxes, image_shape)
        >>> print(areas)
        [1600. 3600.]
    r   rT   Nr[   r   r\   )rE   rU   rV   rW   r^   )r>   rM   heightwidthZbboxes_denormr&   r&   r'   calculate_bbox_areas_in_pixels   s    re   Fz'Literal[('coco', 'pascal_voc', 'yolo')]r   )r>   source_formatrM   rS   r*   c                 C  s^  |dkrt d| d|  tj} t| }| ddddf |ddddf< |dkr| dddf |dddf< | dddf |dddf< | dddf | ddd	f  |ddd	f< | dddf | ddd
f  |ddd
f< n&|dkr|rHt| ddddf dk| ddddf dkB rHt d|  | ddd	f d	 | ddd
f d	  }}| dddf | |dddf< | dddf | |dddf< | dddf | |ddd	f< | dddf | |ddd
f< n$| ddddf |ddddf< |dkrLt|ddddf ||ddddf< |rZt| |S )aN  Convert bounding boxes from a specified format to the format used by albumentations:
    normalized coordinates of top-left and bottom-right corners of the bounding box in the form of
    `(x_min, y_min, x_max, y_max)` e.g. `(0.15, 0.27, 0.67, 0.5)`.

    Args:
        bboxes: A numpy array of bounding boxes with shape (num_bboxes, 4+).
        source_format: Format of the input bounding boxes. Should be 'coco', 'pascal_voc', or 'yolo'.
        image_shape: Image shape (height, width).
        check_validity: Check if all boxes are valid boxes.

    Returns:
        np.ndarray: An array of bounding boxes in albumentations format with shape (num_bboxes, 4+).

    Raises:
        ValueError: If `source_format` is not 'coco', 'pascal_voc', or 'yolo'.
        ValueError: If in YOLO format, any coordinates are not in the range (0, 1].
       cocoyolo
pascal_voczUnknown source_format 8. Supported formats are: 'coco', 'pascal_voc' and 'yolo'N   rh   r   r   r[   r\   ri   zFIn YOLO format all coordinates must be float and in range (0, 1], got )	rG   r^   r_   rU   rW   
zeros_likeanyr
   r   )r>   rf   rM   rS   converted_bboxesZw_halfZh_halfr&   r&   r'   r      s4    

$,0
>*   "$
*)r>   target_formatrM   rS   r*   c                 C  s   |dkrt d| d|r$t|  t| }| ddddf |ddddf< |dkrtt| ddddf |n| ddddf }|dkr$|dddf |dddf< |ddd	f |ddd	f< |ddd
f |dddf  |ddd
f< |dddf |ddd	f  |dddf< n|dkr|dddf |ddd
f  d
 |dddf< |ddd	f |dddf  d
 |ddd	f< |ddd
f |dddf  |ddd
f< |dddf |ddd	f  |dddf< n||ddddf< |S )a  Convert bounding boxes from the format used by albumentations to a specified format.

    Args:
        bboxes: A numpy array of albumentations bounding boxes with shape (num_bboxes, 4+).
                The first 4 columns are [x_min, y_min, x_max, y_max].
        target_format: Required format of the output bounding boxes. Should be 'coco', 'pascal_voc' or 'yolo'.
        image_shape: Image shape (height, width).
        check_validity: Check if all boxes are valid boxes.

    Returns:
        np.ndarray: An array of bounding boxes in the target format with shape (num_bboxes, 4+).

    Raises:
        ValueError: If `target_format` is not 'coco', 'pascal_voc' or 'yolo'.
    rg   zUnknown target_format rk   Nrl   ri   rh   r   r   r[   r\   )rG   r   rU   rm   r   )r>   rp   rM   rS   ro   denormalized_bboxesr&   r&   r'   r   +  s*    

$6
,.
00,.r@   )r>   r*   c           
      C  s  | ddddf dk| ddddf dk@ }t | ddddf d}t | ddddf d}||B |B }t |st t j|dd d d }| | }dddd	gt ||  d d  }|t ||  d d  }td
| d| d| d| dddf | dddf k| dddf | dddf k@ }	t |	st |	 d d }| | }|d |d krtd| dtd| ddS )a  Check if bboxes boundaries are in range 0, 1 and minimums are lesser than maximums.

    Args:
        bboxes: numpy array of shape (num_bboxes, 4+) where first 4 coordinates are x_min, y_min, x_max, y_max.

    Raises:
        ValueError: If any bbox is invalid.
    Nrl   r   r   Zaxisx_miny_minx_maxy_maxz	Expected z
 for bbox z$ to be in the range [0.0, 1.0], got .r[   r\   z.x_max is less than or equal to x_min for bbox z.y_max is less than or equal to y_min for bbox )rU   iscloserH   whererG   )
r>   Zin_rangeZclose_to_zeroZclose_to_oneZvalid_rangeZinvalid_idxZinvalid_bboxZinvalid_coordZinvalid_valueZvalid_orderr&   r&   r'   r   ^  s&    0$@c                 C  s   |dd \}}t | |}t|ddddgf d||ddddgf< t|ddddgf d||ddddgf< t||S )a  Clips the bounding box coordinates to ensure they fit within the boundaries of an image.

    Parameters:
        bboxes (np.ndarray): Array of bounding boxes with shape (num_boxes, 4+) in normalized format.
                             The first 4 columns are [x_min, y_min, x_max, y_max].
        image_shape (Tuple[int, int]): Image shape (height, width).

    Returns:
        np.ndarray: The clipped bounding boxes, normalized to the image dimensions.

    Nr[   r   r   r\   )r   rU   r   r
   )r>   rM   rc   rd   Zdenorm_bboxesr&   r&   r'   clip_bboxes  s
    
..rz   r         ?r   )r>   rM   r   r   r   r   r*   c                 C  s  d}t | dkr(tjg tjdddS t| |}t| |}t||}	t|ddddf |}
|
dddf |
dddf  }|
dddf |
dddf  }||k|	|| k@ |	| || k@ ||| k@ ||| k@ }|| }t |dkr
tjg tjdddS |S )	a  Remove bounding boxes that either lie outside of the visible area by more than min_visibility
    or whose area in pixels is under the threshold set by `min_area`. Also crops boxes to final image size.

    Args:
        bboxes: numpy array of bounding boxes with shape (num_bboxes, 4+).
                The first 4 columns are [x_min, y_min, x_max, y_max].
        image_shape: Image shape (height, width).
        min_area: Minimum area of a bounding box in pixels. Default: 0.0.
        min_visibility: Minimum fraction of area for a bounding box to remain. Default: 0.0.
        min_width: Minimum width of a bounding box in pixels. Default: 0.0.
        min_height: Minimum height of a bounding box in pixels. Default: 0.0.

    Returns:
        numpy array of filtered bounding boxes.
    gHz>r   rT   rl   Nr[   r\   r   )rE   rU   rV   rW   Zreshapere   rz   r   )r>   rM   r   r   r   r   epsilonZdenormalized_box_areasZclipped_bboxesZclipped_box_areasrq   Zclipped_widthsZclipped_heightsmaskZfiltered_bboxesr&   r&   r'   r     s*    


  


	znp.ndarray | None)r>   erosion_rater*   c                 C  s   | j s
dS |dkrdS | jd dkr4| d dd S d}tj| ddddf dd\}}tj| ddddf dd\}}|| }|| }|| d }	|| d }
||	7 }||
7 }||	8 }||
8 }t|| |k st|| |k rdS tj||||gtjd	S )
a.  Calculate union of bounding boxes. Boxes could be in albumentations or Pascal Voc format.

    Args:
        bboxes (np.ndarray): List of bounding boxes
        erosion_rate (float): How much each bounding box can be shrunk, useful for erosive cropping.
            Set this in range [0, 1]. 0 will not be erosive at all, 1.0 can make any bbox lose its volume.

    Returns:
        np.ndarray | None: A bounding box `(x_min, y_min, x_max, y_max)` or None if no bboxes are given or if
                    the bounding boxes become invalid after erosion.
    Nr   r   rl   gư>r[   rr   g      ?rT   )sizeshaperU   minmaxabsrV   rW   )r>   r~   r|   rs   rt   ru   rv   rd   rc   Z	erosion_xZ	erosion_yr&   r&   r'   r     s(    "" )masksr*   c                 C  s   t j| dd}t j| dd}t j| jd dft jd}tt||D ]~\}\}}t |rdt |svddddg||< qDt |d ddg \}}t |d ddg \}	}
|	||
d |d g||< qD|S )a  Create bounding boxes from binary masks (fast version)

    Args:
        masks (np.ndarray): Binary masks of shape (N, H, W) where N is the number of masks,
                            and H, W are the height and width of each mask.

    Returns:
        np.ndarray: An array of bounding boxes with shape (N, 4), where each row is
                    (x_min, y_min, x_max, y_max).
    r[   rr   r   r   rl   rT   )rU   rn   zerosr   Zint32	enumeratezipry   )r   r`   ra   r>   rB   rowcolrt   rv   rs   ru   r&   r&   r'   bboxes_from_masks  s    r   )r>   	img_shaper*   c                 C  s   |dd \}}t jt| ||ft jd}t jd|d|f \}}t| ddddf tD ]4\}\}}	}
}||k||
k @ |	|k@ ||k @ ||< qb|S )a  Create binary masks from multiple bounding boxes

    Args:
        bboxes: Array of bounding boxes with shape (N, 4), where N is the number of boxes
        img_shape: Image shape (height, width)

    Returns:
        masks: Array of binary masks with shape (N, height, width)

    Nr[   rT   rl   )rU   r   rE   Zuint8Zogridr   r_   int)r>   r   rc   rd   r   yxrB   rs   rt   ru   rv   r&   r&   r'   masks_from_bboxes-  s    .&r   )F)F)r   r   r{   r{   )
__future__r   typingr   r   r   ZnumpyrU   Z"albumentations.augmentations.utilsr   utilsr   r	   __all__rF   r   r   r
   r   re   r   r   r   rz   r   r   r   r   r&   r&   r&   r'   <module>   sP   Q3( : 2$,    :+