U
    h#R                    @  s8  d dl mZ d dlZd dlmZmZmZmZ d dlm	Z	 d dl
Z
d dlZd dlZd dlmZmZ d dlmZmZmZmZmZ d dlmZmZ d dlmZ d d	lmZ d d
lm Z m!Z! d dl"m#Z#m$Z$m%Z%m&Z&m'Z' d dl(m)Z)m*Z* d dl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 d dl5m6Z6 ddl7m8Z9 ddddddddddddddgZ:G dd  d e*Z;G d!d de;Z<G d"d de*Z=G d#d de*Z>G d$d de>Z?G d%d de*Z@G d&d de*ZAG d'd de*ZBG d(d de*ZCG d)d de*ZDG d*d de*ZEG d+d de;ZFG d,d de;ZGG d-d de*ZHG d.d de*ZIdS )/    )annotationsN)AnyLiteralTuplecast)warn)hflipvflip)AfterValidatorFieldValidationInfofield_validatormodel_validator)	AnnotatedSelf)random_utils)check_range)denormalize_bboxesnormalize_bboxes)BorderModeTypeInterpolationTypeNonNegativeFloatRangeTypeSymmetricRangeTypecheck_1plus)BaseTransformInitSchemaDualTransform)	BIG_INTEGER	ColorTypeD4TypePositionType
ScalarTypeScaleFloatTypeScaleIntTypeTargetsd4_group_elements)to_tuple   )
functionalShiftScaleRotateElasticTransformPerspectiveAffinePiecewiseAffineVerticalFlipHorizontalFlipFlip	TransposeOpticalDistortionGridDistortionPadIfNeededD4GridElasticDeformc                      s   e Zd ZdZejejejejfZ	G dd de
Zejejddddfdddddd	d
 fddZddddddddZddddddddZddddddddZddddddddZddddZ  ZS )BaseDistortiona  Base class for distortion-based transformations.

    This class provides a foundation for implementing various types of image distortions,
    such as optical distortions, grid distortions, and elastic transformations. It handles
    the common operations of applying distortions to images, masks, bounding boxes, and keypoints.

    Args:
        interpolation (int): Interpolation method to be used for image transformation.
            Should be one of the OpenCV interpolation types (e.g., cv2.INTER_LINEAR,
            cv2.INTER_CUBIC). Default: cv2.INTER_LINEAR
        border_mode (int): Border mode to be used for handling pixels outside the image boundaries.
            Should be one of the OpenCV border types (e.g., cv2.BORDER_REFLECT_101,
            cv2.BORDER_CONSTANT). Default: cv2.BORDER_REFLECT_101
        value (int, float, list of int, list of float, optional): Padding value if border_mode is
            cv2.BORDER_CONSTANT. Default: None
        mask_value (ColorType | None): Padding value for mask if
            border_mode is cv2.BORDER_CONSTANT. Default: None
        p (float): Probability of applying the transform. Default: 0.5

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - This is an abstract base class and should not be used directly.
        - Subclasses should implement the `get_params_dependent_on_data` method to generate
          the distortion maps (map_x and map_y).
        - The distortion is applied consistently across all targets (image, mask, bboxes, keypoints)
          to maintain coherence in the augmented data.

    Example of a subclass:
        class CustomDistortion(BaseDistortion):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                # Add custom parameters here

            def get_params_dependent_on_data(self, params, data):
                # Generate and return map_x and map_y based on the distortion logic
                return {"map_x": map_x, "map_y": map_y}

            def get_transform_init_args_names(self):
                return super().get_transform_init_args_names() + ("custom_param1", "custom_param2")
    c                   @  s.   e Zd ZU ded< ded< ded< ded< dS )	zBaseDistortion.InitSchemar   interpolationr   border_modeColorType | Nonevalue
mask_valueN__name__
__module____qualname____annotations__ rA   rA   U/tmp/pip-unpacked-wheel-e8onvpoz/albumentations/augmentations/geometric/transforms.py
InitSchemak   s   
rC   N      ?intr9   bool | Nonefloatr7   r8   r:   r;   always_applypc                   s,   t  j||d || _|| _|| _|| _d S NrJ   rI   )super__init__r7   r8   r:   r;   )selfr7   r8   r:   r;   rI   rJ   	__class__rA   rB   rN   q   s
    	zBaseDistortion.__init__
np.ndarrayr   )imgmap_xmap_yparamsreturnc                 K  s   t |||| j| j| jS N)
fgeometric
distortionr7   r8   r:   )rO   rS   rT   rU   rV   rA   rA   rB   apply   s    zBaseDistortion.apply)maskrT   rU   rV   rW   c                 K  s   t |||tj| j| jS rX   )rY   rZ   cv2INTER_NEARESTr8   r;   )rO   r\   rT   rU   rV   rA   rA   rB   apply_to_mask   s    zBaseDistortion.apply_to_mask)bboxesrT   rU   rV   rW   c                 K  s8   |d d d }t ||}t||||| j}t||S Nshape   )r   rY   Zdistortion_bboxesr8   r   )rO   r`   rT   rU   rV   image_shapebboxes_denormZbboxes_returnedrA   rA   rB   apply_to_bboxes   s    
zBaseDistortion.apply_to_bboxes)	keypointsrT   rU   rV   rW   c                 K  s   t ||||d S Nrb   )rY   Zdistortion_keypoints)rO   rg   rT   rU   rV   rA   rA   rB   apply_to_keypoints   s    z!BaseDistortion.apply_to_keypointstuple[str, ...]rW   c                 C  s   dS )N)r7   r8   r:   r;   rA   rO   rA   rA   rB   get_transform_init_args_names   s    z,BaseDistortion.get_transform_init_args_names)r=   r>   r?   __doc__r#   IMAGEMASKBBOXES	KEYPOINTS_targetsr   rC   r]   INTER_LINEARBORDER_REFLECT_101rN   r[   r_   rf   ri   rm   __classcell__rA   rA   rP   rB   r6   :   s   .	r6   c                      s   e Zd ZdZG dd dejZddejejddddddf
d	d	d
d
dddddd	d
 fddZ	ddddddZ
dd fddZ  ZS )r)   a  Apply elastic deformation to images, masks, bounding boxes, and keypoints.

    This transformation introduces random elastic distortions to the input data. It's particularly
    useful for data augmentation in training deep learning models, especially for tasks like
    image segmentation or object detection where you want to maintain the relative positions of
    features while introducing realistic deformations.

    The transform works by generating random displacement fields and applying them to the input.
    These fields are smoothed using a Gaussian filter to create more natural-looking distortions.

    Args:
        alpha (float): Scaling factor for the random displacement fields. Higher values result in
            more pronounced distortions. Default: 1.0
        sigma (float): Standard deviation of the Gaussian filter used to smooth the displacement
            fields. Higher values result in smoother, more global distortions. Default: 50.0
        interpolation (int): Interpolation method to be used for image transformation. Should be one
            of the OpenCV interpolation types. Default: cv2.INTER_LINEAR
        border_mode (int): Border mode to be used for handling pixels outside the image boundaries.
            Should be one of the OpenCV border types. Default: cv2.BORDER_REFLECT_101
        value (int, float, list of int, list of float, optional): Padding value if border_mode is
            cv2.BORDER_CONSTANT. Default: None
        mask_value (int, float, list of int, list of float, optional): Padding value for mask if
            border_mode is cv2.BORDER_CONSTANT. Default: None
        approximate (bool): Whether to use an approximate version of the elastic transform. If True,
            uses a fixed kernel size for Gaussian smoothing, which can be faster but potentially
            less accurate for large sigma values. Default: False
        same_dxdy (bool): Whether to use the same random displacement field for both x and y
            directions. Can speed up the transform at the cost of less diverse distortions. Default: False
        p (float): Probability of applying the transform. Default: 0.5

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - The transform will maintain consistency across all targets (image, mask, bboxes, keypoints)
          by using the same displacement fields for all.
        - The 'approximate' parameter determines whether to use a precise or approximate method for
          generating displacement fields. The approximate method can be faster but may be less
          accurate for large sigma values.
        - Bounding boxes that end up outside the image after transformation will be removed.
        - Keypoints that end up outside the image after transformation will be removed.

    Example:
        >>> import albumentations as A
        >>> transform = A.Compose([
        ...     A.ElasticTransform(alpha=1, sigma=50, p=0.5),
        ... ])
        >>> transformed = transform(image=image, mask=mask, bboxes=bboxes, keypoints=keypoints)
        >>> transformed_image = transformed['image']
        >>> transformed_mask = transformed['mask']
        >>> transformed_bboxes = transformed['bboxes']
        >>> transformed_keypoints = transformed['keypoints']
    c                   @  s.   e Zd ZU ded< ded< ded< ded< dS )	zElasticTransform.InitSchemazAnnotated[float, Field(ge=0)]alphazAnnotated[float, Field(ge=1)]sigmaboolapproximate	same_dxdyNr<   rA   rA   rA   rB   rC      s   
rC   r&   2   NFrD   rG   rE   z$ScalarType | list[ScalarType] | NonerF   ry   )
rw   rx   r7   r8   r:   r;   rI   rz   r{   rJ   c                   s4   t  j||||||
d || _|| _|| _|	| _d S NrH   )rM   rN   rw   rx   rz   r{   )rO   rw   rx   r7   r8   r:   r;   rI   rz   r{   rJ   rP   rA   rB   rN      s    zElasticTransform.__init__dict[str, Any]rV   datarW   c                 C  s   |d d d \}}| j rdnd}tj||f| j| j| j|t d\}}t	t
|t
|\}}	t|| }
t|	| }|
|dS )Nrb   rc   r   r   )   r   )r{   kernel_sizerandom_staterT   rU   )rz   rY   Zgenerate_displacement_fieldsrw   rx   r{   r   get_random_statenpmeshgridZarangefloat32)rO   rV   r   heightwidthr   dxdyxyrT   rU   rA   rA   rB   get_params_dependent_on_data   s    
	z-ElasticTransform.get_params_dependent_on_datarj   rk   c                   s   t   dS )Nrw   rx   rz   r{   )rw   rx   rz   r{   rM   rm   rl   rP   rA   rB   rm     s    z.ElasticTransform.get_transform_init_args_namesr=   r>   r?   rn   r6   rC   r]   rt   ru   rN   r   rm   rv   rA   rA   rP   rB   r)      s   9&c                      s   e Zd ZdZejejejejfZ	G dd de
Zddejdddejdd	f	d
ddddddddd	 fddZdddddddddZdddddddddZdddddddddZddddddddd Zd!d!d!d"d#d$Zd%d&d'd(Z  ZS ))r*   a)
  Apply random four point perspective transformation to the input.

    Args:
        scale (float or tuple of float): Standard deviation of the normal distributions. These are used to sample
            the random distances of the subimage's corners from the full image's corners.
            If scale is a single float value, the range will be (0, scale).
            Default: (0.05, 0.1).
        keep_size (bool): Whether to resize image back to its original size after applying the perspective transform.
            If set to False, the resulting images may end up having different shapes.
            Default: True.
        pad_mode (OpenCV flag): OpenCV border mode used for padding.
            Default: cv2.BORDER_CONSTANT.
        pad_val (int, float, list of int, list of float): Padding value if border_mode is cv2.BORDER_CONSTANT.
            Default: 0.
        mask_pad_val (int, float, list of int, list of float): Padding value for mask if border_mode is
            cv2.BORDER_CONSTANT. Default: 0.
        fit_output (bool): If True, the image plane size and position will be adjusted to still capture
            the whole image after perspective transformation. This is followed by image resizing if keep_size is set
            to True. If False, parts of the transformed image may be outside of the image plane.
            This setting should not be set to True when using large scale values as it could lead to very large images.
            Default: False.
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, keypoints, bboxes

    Image types:
        uint8, float32

    Note:
        This transformation creates a perspective effect by randomly moving the four corners of the image.
        The amount of movement is controlled by the 'scale' parameter.

        When 'keep_size' is True, the output image will have the same size as the input image,
        which may cause some parts of the transformed image to be cut off or padded.

        When 'fit_output' is True, the transformation ensures that the entire transformed image is visible,
        which may result in a larger output image if keep_size is False.

    Example:
        >>> import numpy as np
        >>> import albumentations as A
        >>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
        >>> transform = A.Compose([
        ...     A.Perspective(scale=(0.05, 0.1), keep_size=True, always_apply=False, p=0.5),
        ... ])
        >>> result = transform(image=image)
        >>> transformed_image = result['image']
    c                   @  sF   e Zd ZU ded< ded< ded< ded< ded	< ded
< ded< dS )zPerspective.InitSchemar   scalery   	keep_sizer   pad_moder9   pad_valmask_pad_val
fit_outputr   r7   Nr<   rA   rA   rA   rB   rC   @  s   
rC   )皙?皙?Tr   FNrD   r!   ry   rE   r   rF   rG   )	r   r   r   r   r   r   r7   rI   rJ   c
           
        sL   t  j|	|d ttttf || _|| _|| _|| _|| _	|| _
|| _d S )N)rI   )rM   rN   r   r   rG   r   r   r   r   r   r   r7   )
rO   r   r   r   r   r   r   r7   rI   rJ   rP   rA   rB   rN   I  s    zPerspective.__init__rR   r   )rS   matrix
max_height	max_widthrV   rW   c              
   K  s    t ||||| j| j| j| jS rX   )rY   perspectiver   r   r   r7   )rO   rS   r   r   r   rV   rA   rA   rB   r[   ^  s    zPerspective.apply)r\   r   r   r   rV   rW   c              
   K  s    t ||||| j| j| jtjS rX   )rY   r   r   r   r   r]   r^   )rO   r\   r   r   r   rV   rA   rA   rB   r_   q  s    zPerspective.apply_to_mask)r`   r   r   r   rV   rW   c                 K  s   t ||d |||| jS rh   )rY   Zperspective_bboxesr   )rO   r`   r   r   r   rV   rA   rA   rB   rf     s    zPerspective.apply_to_bboxes)rg   r   r   r   rV   rW   c                 K  s   t ||d |||| jS rh   )rY   Zperspective_keypointsr   )rO   rg   r   r   r   rV   rA   rA   rB   ri     s    zPerspective.apply_to_keypointsr~   r   c           
      C  sp   |d d d }t j| j }t }t|||}t|}t|\}}}	| j	rdt
||\}}}	||	|dS )Nrb   rc   )r   r   r   )randomuniformr   r   r   rY   Zgenerate_perspective_pointsZorder_pointsZcompute_perspective_paramsr   Zexpand_transform)
rO   rV   r   rd   r   r   Zpointsr   r   r   rA   rA   rB   r     s    
z(Perspective.get_params_dependent_on_datarj   rk   c                 C  s   dS )N)r   r   r   r   r   r   r7   rA   rl   rA   rA   rB   rm     s    z)Perspective.get_transform_init_args_names)r=   r>   r?   rn   r#   ro   rp   rr   rq   rs   r   rC   r]   BORDER_CONSTANTrt   rN   r[   r_   rf   ri   r   rm   rv   rA   rA   rP   rB   r*     s&   2$c                      sn  e Zd ZdZejejejejfZ	G dd de
Zdddddejejddejddddddfd	d	d
dd	dddddddddddd fddZddddZedCdddddddZed	d	d d!d"d#Zd$d%d&d d$d'd(d)Zd$d%d&d d$d*d+d,Zd$d-d&d d$d.d/d0Zd$d-dd d$d1d2d3Zed4ddd5d6d7d8Zdddd9d:d;Zd&d<d=d>d?Zd@ddAdBZ  ZS )Dr+   a  Augmentation to apply affine transformations to images.

    Affine transformations involve:

        - Translation ("move" image on the x-/y-axis)
        - Rotation
        - Scaling ("zoom" in/out)
        - Shear (move one side of the image, turning a square into a trapezoid)

    All such transformations can create "new" pixels in the image without a defined content, e.g.
    if the image is translated to the left, pixels are created on the right.
    A method has to be defined to deal with these pixel values.
    The parameters `cval` and `mode` of this class deal with this.

    Some transformations involve interpolations between several pixels
    of the input image to generate output pixel values. The parameters `interpolation` and
    `mask_interpolation` deals with the method of interpolation used for this.

    Args:
        scale (number, tuple of number or dict): Scaling factor to use, where ``1.0`` denotes "no change" and
            ``0.5`` is zoomed out to ``50`` percent of the original size.
                * If a single number, then that value will be used for all images.
                * If a tuple ``(a, b)``, then a value will be uniformly sampled per image from the interval ``[a, b]``.
                  That the same range will be used for both x- and y-axis. To keep the aspect ratio, set
                  ``keep_ratio=True``, then the same value will be used for both x- and y-axis.
                * If a dictionary, then it is expected to have the keys ``x`` and/or ``y``.
                  Each of these keys can have the same values as described above.
                  Using a dictionary allows to set different values for the two axis and sampling will then happen
                  *independently* per axis, resulting in samples that differ between the axes. Note that when
                  the ``keep_ratio=True``, the x- and y-axis ranges should be the same.
        translate_percent (None, number, tuple of number or dict): Translation as a fraction of the image height/width
            (x-translation, y-translation), where ``0`` denotes "no change"
            and ``0.5`` denotes "half of the axis size".
                * If ``None`` then equivalent to ``0.0`` unless `translate_px` has a value other than ``None``.
                * If a single number, then that value will be used for all images.
                * If a tuple ``(a, b)``, then a value will be uniformly sampled per image from the interval ``[a, b]``.
                  That sampled fraction value will be used identically for both x- and y-axis.
                * If a dictionary, then it is expected to have the keys ``x`` and/or ``y``.
                  Each of these keys can have the same values as described above.
                  Using a dictionary allows to set different values for the two axis and sampling will then happen
                  *independently* per axis, resulting in samples that differ between the axes.
        translate_px (None, int, tuple of int or dict): Translation in pixels.
                * If ``None`` then equivalent to ``0`` unless `translate_percent` has a value other than ``None``.
                * If a single int, then that value will be used for all images.
                * If a tuple ``(a, b)``, then a value will be uniformly sampled per image from
                  the discrete interval ``[a..b]``. That number will be used identically for both x- and y-axis.
                * If a dictionary, then it is expected to have the keys ``x`` and/or ``y``.
                  Each of these keys can have the same values as described above.
                  Using a dictionary allows to set different values for the two axis and sampling will then happen
                  *independently* per axis, resulting in samples that differ between the axes.
        rotate (number or tuple of number): Rotation in degrees (**NOT** radians), i.e. expected value range is
            around ``[-360, 360]``. Rotation happens around the *center* of the image,
            not the top left corner as in some other frameworks.
                * If a number, then that value will be used for all images.
                * If a tuple ``(a, b)``, then a value will be uniformly sampled per image from the interval ``[a, b]``
                  and used as the rotation value.
        shear (number, tuple of number or dict): Shear in degrees (**NOT** radians), i.e. expected value range is
            around ``[-360, 360]``, with reasonable values being in the range of ``[-45, 45]``.
                * If a number, then that value will be used for all images as
                  the shear on the x-axis (no shear on the y-axis will be done).
                * If a tuple ``(a, b)``, then two value will be uniformly sampled per image
                  from the interval ``[a, b]`` and be used as the x- and y-shear value.
                * If a dictionary, then it is expected to have the keys ``x`` and/or ``y``.
                  Each of these keys can have the same values as described above.
                  Using a dictionary allows to set different values for the two axis and sampling will then happen
                  *independently* per axis, resulting in samples that differ between the axes.
        interpolation (int): OpenCV interpolation flag.
        mask_interpolation (int): OpenCV interpolation flag.
        cval (number or sequence of number): The constant value to use when filling in newly created pixels.
            (E.g. translating by 1px to the right will create a new 1px-wide column of pixels
            on the left of the image).
            The value is only used when `mode=constant`. The expected value range is ``[0, 255]`` for ``uint8`` images.
        cval_mask (number or tuple of number): Same as cval but only for masks.
        mode (int): OpenCV border flag.
        fit_output (bool): If True, the image plane size and position will be adjusted to tightly capture
            the whole image after affine transformation (`translate_percent` and `translate_px` are ignored).
            Otherwise (``False``),  parts of the transformed image may end up outside the image plane.
            Fitting the output shape can be useful to avoid corners of the image being outside the image plane
            after applying rotations. Default: False
        keep_ratio (bool): When True, the original aspect ratio will be kept when the random scale is applied.
            Default: False.
        rotate_method (Literal["largest_box", "ellipse"]): rotation method used for the bounding boxes.
            Should be one of "largest_box" or "ellipse"[1]. Default: "largest_box"
        balanced_scale (bool): When True, scaling factors are chosen to be either entirely below or above 1,
            ensuring balanced scaling. Default: False.

            This is important because without it, scaling tends to lean towards upscaling. For example, if we want
            the image to zoom in and out by 2x, we may pick an interval [0.5, 2]. Since the interval [0.5, 1] is
            three times smaller than [1, 2], values above 1 are picked three times more often if sampled directly
            from [0.5, 2]. With `balanced_scale`, the  function ensures that half the time, the scaling
            factor is picked from below 1 (zooming out), and the other half from above 1 (zooming in).
            This makes the zooming in and out process more balanced.
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, keypoints, bboxes

    Image types:
        uint8, float32

    Reference:
        [1] https://arxiv.org/abs/2109.13488

    c                   @  s   e Zd ZU edddZded< edddZded< edddZd	ed
< edddZded< edddZ	ded< e
jZded< e
jZded< edddZded< edddZded< e
jZded< ded< ded< dZd ed!< d"ed#< dS )$zAffine.InitSchemaNz:Scaling factor or dictionary for independent axis scaling.)defaultdescription&ScaleFloatType | dict[str, Any] | Noner   z1Translation as a fraction of the image dimension.translate_percentzTranslation in pixels.$ScaleIntType | dict[str, Any] | Nonetranslate_pxzRotation angle in degrees.ScaleFloatType | NonerotatezShear angle in degrees.shearr   r7   mask_interpolationr   z Value used for constant padding.r   cvalz%Value used for mask constant padding.	cval_maskr   modezZAnnotated[bool, Field(default=False, description='Adjust output to capture whole image.')]r   zXAnnotated[bool, Field(default=False, description='Maintain aspect ratio when scaling.')]
keep_ratiolargest_box#Literal[('largest_box', 'ellipse')]rotate_methodzJAnnotated[bool, Field(default=False, description='Use balanced scaling.')]balanced_scale)r=   r>   r?   r   r   r@   r   r   r   r   r]   rt   r7   r^   r   r   r   r   r   r   rA   rA   rA   rB   rC   &  s4   
rC   Nr   Fr   rD   r   r   r   rE   r   ry   r   rF   rG   )r   r   r   r   r   r7   r   r   r   r   r   r   r   r   rI   rJ   c                   s(  t  j||d |||||g}tdd |D rTddd}ddd}d}ddd}n0|d k	r`|nd	}|d k	rp|nd
}|d k	r|nd
}|| _|| _|| _|	| _|
| _| |d| _	| 
||\| _| _t||| _|| _| |d| _|| _|| _|| _| jr$| j	d | j	d kr$td| j	 d S )NrL   c                 s  s   | ]}|d kV  qd S rX   rA   ).0rJ   rA   rA   rB   	<genexpr>Y  s     z"Affine.__init__.<locals>.<genexpr>)g?g?r   r   gr   )i   )i
         ?        r   r   r   r   zJWhen keep_ratio is True, the x and y scale range should be identical. got )rM   rN   allr7   r   r   r   r   _handle_dict_argr   _handle_translate_argr   r   r%   r   r   r   r   r   r   
ValueError)rO   r   r   r   r   r   r7   r   r   r   r   r   r   r   r   rI   rJ   rV   rP   rA   rB   rN   C  s2    

zAffine.__init__rj   rk   c                 C  s   dS )N)r7   r   r   r   r   r   r   r   r   r   r   r   r   r   rA   rl   rA   rA   rB   rm   t  s    z$Affine.get_transform_init_args_namesr   z,float | tuple[float, float] | dict[str, Any]strr~   )valnamer   rW   c                 C  sn   t | trXd| kr*d| kr*td| d| d|}| d|}t||t||dS t| | t| | dS )Nr   r   z	Expected zJ dictionary to contain at least key "x" or key "y". Found neither of them.r   )
isinstancedictr   getr%   )r   r   r   r   r   rA   rA   rB   r     s    

zAffine._handle_dict_argr   )r   r   rW   c                 C  sp   |d kr|d krd}|d k	r0|d k	r0d}t ||d k	rL| j|ddd|fS |d kr`d}t ||| |dfS )Nr   zYExpected either translate_percent or translate_px to be provided, but both were provided.r   r   r   ztranslate_px is None.r   )r   r   )clsr   r   msgrA   rA   rB   r     s    zAffine._handle_translate_argrR   z%skimage.transform.ProjectiveTransformtuple[int, int])rS   r   output_shaperV   rW   c                 K  s   t j||| j| j| j|dS N)r7   r   r   r   )rY   warp_affiner7   r   r   )rO   rS   r   r   rV   rA   rA   rB   r[     s    zAffine.apply)r\   r   r   rV   rW   c                 K  s   t j||| j| j| j|dS r   )rY   r   r   r   r   )rO   r\   r   r   rV   rA   rA   rB   r_     s    zAffine.apply_to_maskz!skimage.transform.AffineTransform)r`   bbox_matrixr   rV   rW   c                 K  s$   t ||| j|d d d | j|S ra   )rY   Zbboxes_affiner   r   )rO   r`   r   r   rV   rA   rA   rB   rf     s    zAffine.apply_to_bboxes)rg   r   r   rV   rW   c                 K  s   t |||d || jS rh   )rY   Zkeypoints_affiner   )rO   rg   r   r   rV   rA   rA   rB   ri     s    zAffine.apply_to_keypointszdict[str, tuple[float, float]]zfgeometric.ScaleDict)r   r   r   rW   c           	      C  s   i }|r|   D ]\}}|d dk r0|d dfnd }|d dkrLd|d fnd }|d k	rp|d k	rpt||g}n*|d k	r~|}n|d k	r|}ntd| tj| ||< qndd |   D }|r|d |d< ttj|S )	Nr   r&   r   z9Both lower_interval and upper_interval are None for key: c                 S  s   i | ]\}}|t j| qS rA   r   r   r   keyr:   rA   rA   rB   
<dictcomp>  s      z$Affine.get_scale.<locals>.<dictcomp>r   r   )itemsr   choicer   r   r   rY   Z	ScaleDict)	r   r   r   Zresult_scaler   r:   Zlower_intervalZupper_intervalZselected_intervalrA   rA   rB   	get_scale  s"    zAffine.get_scaler   c                 C  s   |d d d }|  |}|  }| | j| j| j}tj| j  }t	
|}t	|}	t	|||||}
t	|||||	}| jrt	|
|\}
}t	||\}}n|}|||
||dS )Nrb   rc   )r   r   r   r   r   )_get_translate_params_get_shear_paramsr   r   r   r   r   r   r   rY   centerZcenter_bboxZ#create_affine_transformation_matrixr   Z compute_affine_warp_output_shape)rO   rV   r   rd   	translater   r   r   Zimage_shiftZ
bbox_shiftr   r   r   _rA   rA   rB   r     s&    


z#Affine.get_params_dependent_on_datazfgeometric.TranslateDict)rd   rW   c                 C  s   |d d \}}| j d k	r6ttjdd | j  D S | jd k	rvdd | j D }ttj|d | |d | dS ttjdddS )	Nrc   c                 S  s   i | ]\}}|t j| qS rA   r   randintr   rA   rA   rB   r   %  s      z0Affine._get_translate_params.<locals>.<dictcomp>c                 S  s   i | ]\}}|t j| qS rA   r   r   rA   rA   rB   r   (  s      r   r   r   r   )r   r   rY   ZTranslateDictr   r   )rO   rd   r   r   r   rA   rA   rB   r      s    

"zAffine._get_translate_paramszfgeometric.ShearDictc                 C  s   t tjdd | j D S )Nc                 S  s   i | ]\}}|t j|  qS rA   r   r   rA   rA   rB   r   -  s      z,Affine._get_shear_params.<locals>.<dictcomp>)r   rY   Z	ShearDictr   r   rl   rA   rA   rB   r   ,  s    zAffine._get_shear_params)r   )r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r   rC   r]   rt   r^   r   rN   rm   staticmethodr   classmethodr   r[   r_   rf   ri   r   r   r   r   rv   rA   rA   rP   rB   r+     sF   i21 	c                      s   e Zd ZdZejejejejfZ	G dd de
Zdddejejddddd	dd
fddddddddddddd fddZddddZ  ZS )r(   a  Randomly apply affine transforms: translate, scale and rotate the input.

    Args:
        shift_limit ((float, float) or float): shift factor range for both height and width. If shift_limit
            is a single float value, the range will be (-shift_limit, shift_limit). Absolute values for lower and
            upper bounds should lie in range [-1, 1]. Default: (-0.0625, 0.0625).
        scale_limit ((float, float) or float): scaling factor range. If scale_limit is a single float value, the
            range will be (-scale_limit, scale_limit). Note that the scale_limit will be biased by 1.
            If scale_limit is a tuple, like (low, high), sampling will be done from the range (1 + low, 1 + high).
            Default: (-0.1, 0.1).
        rotate_limit ((int, int) or int): rotation range. If rotate_limit is a single int value, the
            range will be (-rotate_limit, rotate_limit). Default: (-45, 45).
        interpolation (OpenCV flag): flag that is used to specify the interpolation algorithm. Should be one of:
            cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4.
            Default: cv2.INTER_LINEAR.
        border_mode (OpenCV flag): flag that is used to specify the pixel extrapolation method. Should be one of:
            cv2.BORDER_CONSTANT, cv2.BORDER_REPLICATE, cv2.BORDER_REFLECT, cv2.BORDER_WRAP, cv2.BORDER_REFLECT_101.
            Default: cv2.BORDER_REFLECT_101
        value (int, float, list of int, list of float): padding value if border_mode is cv2.BORDER_CONSTANT.
        mask_value (int, float,
                    list of int,
                    list of float): padding value if border_mode is cv2.BORDER_CONSTANT applied for masks.
        shift_limit_x ((float, float) or float): shift factor range for width. If it is set then this value
            instead of shift_limit will be used for shifting width.  If shift_limit_x is a single float value,
            the range will be (-shift_limit_x, shift_limit_x). Absolute values for lower and upper bounds should lie in
            the range [-1, 1]. Default: None.
        shift_limit_y ((float, float) or float): shift factor range for height. If it is set then this value
            instead of shift_limit will be used for shifting height.  If shift_limit_y is a single float value,
            the range will be (-shift_limit_y, shift_limit_y). Absolute values for lower and upper bounds should lie
            in the range [-, 1]. Default: None.
        rotate_method (str): rotation method used for the bounding boxes. Should be one of "largest_box" or "ellipse".
            Default: "largest_box"
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, keypoints, bboxes

    Image types:
        uint8, float32

    c                   @  s   e Zd ZU dZded< dZded< dZded< ejZ	ded	< ej
Zd
ed< dZded< dZded< eddZded< eddZded< dZded< eddddddZededddd d!d"ZdS )#zShiftScaleRotate.InitSchemag      g      ?r   shift_limitr   scale_limiti-   rotate_limitr   r7   r   r8   r   r   r:   r;   Nr   r   shift_limit_xshift_limit_yr   r   r   afterr   r   rk   c                 C  sd   d}t | jd k	r| jn| j| _t| jf|d  t | jd k	rD| jn| j| _t| jf|d  | S )Nr&   r   r   )r   )r   )r%   r   r   r   r   )rO   boundsrA   rA   rB   check_shift_limiti  s    z-ShiftScaleRotate.InitSchema.check_shift_limitr!   r   r:   inforW   c                 C  s4   dt df}t|dd}t|f|t|jf  |S )Nr   infr   Zbias)rG   r%   r   r   
field_namer   r:   r   r   resultrA   rA   rB   check_scale_limitr  s    z-ShiftScaleRotate.InitSchema.check_scale_limit)r=   r>   r?   r   r@   r   r   r]   rt   r7   ru   r8   r:   r;   r   r   r   r   r   r   r   r   r   rA   rA   rA   rB   rC   ]  s   
rC   r   r   r   r   Nr   rD   r!   rE   r   r   r   rF   rG   )r   r   r   r7   r8   r:   r;   r   r   r   rI   rJ   c                   s   t  j|||	d|d|tj|||dd|
||d tdtdd ttttf || _	ttttf |	| _
ttttf || _ttttf || _|| _|| _|| _d S )Nr   r   F)r   r   r   r   r7   r   r   r   r   r   r   r   rI   rJ   zDShiftScaleRotate is deprecated. Please use Affine transform instead.rc   
stacklevel)rM   rN   r]   r^   r   DeprecationWarningr   r   rG   r   r   r   rE   r   r8   r:   r;   )rO   r   r   r   r7   r8   r:   r;   r   r   r   rI   rJ   rP   rA   rB   rN   z  s8    zShiftScaleRotate.__init__r~   rk   c              
   C  s2   | j | jt| jdd| j| j| j| j| j| j	d	S )Ng      r   )	r   r   r   r   r7   r8   r:   r;   r   )
r   r   r%   r   r   r7   r8   r:   r;   r   rl   rA   rA   rB   get_transform_init_args  s    z(ShiftScaleRotate.get_transform_init_args)r=   r>   r?   rn   r#   ro   rp   rr   rq   rs   r   rC   r]   rt   ru   rN   r   rv   rA   rA   rP   rB   r(   0  s"   **,c                      s   e Zd ZdZejejejejfZ	G dd de
Zdddejejddddd	d
dfddddddddddddd fddZddddZddddddZddd dd!d"d#Zddd dd$d%d&Zddd dd'd(d)Zddd dd*d+d,Z  ZS )-r,   a%  Apply piecewise affine transformations to the input image.

    This augmentation places a regular grid of points on an image and randomly moves the neighborhood of these points
    around via affine transformations. This leads to local distortions in the image.

    Args:
        scale (tuple[float, float] | float): Standard deviation of the normal distributions. These are used to sample
            the random distances of the subimage's corners from the full image's corners.
            If scale is a single float value, the range will be (0, scale).
            Recommended values are in the range (0.01, 0.05) for small distortions,
            and (0.05, 0.1) for larger distortions. Default: (0.03, 0.05).
        nb_rows (tuple[int, int] | int): Number of rows of points that the regular grid should have.
            Must be at least 2. For large images, you might want to pick a higher value than 4.
            If a single int, then that value will always be used as the number of rows.
            If a tuple (a, b), then a value from the discrete interval [a..b] will be uniformly sampled per image.
            Default: 4.
        nb_cols (tuple[int, int] | int): Number of columns of points that the regular grid should have.
            Must be at least 2. For large images, you might want to pick a higher value than 4.
            If a single int, then that value will always be used as the number of columns.
            If a tuple (a, b), then a value from the discrete interval [a..b] will be uniformly sampled per image.
            Default: 4.
        interpolation (int): The order of interpolation. The order has to be in the range 0-5:
             - 0: Nearest-neighbor
             - 1: Bi-linear (default)
             - 2: Bi-quadratic
             - 3: Bi-cubic
             - 4: Bi-quartic
             - 5: Bi-quintic
        mask_interpolation (int): The order of interpolation for masks. Similar to 'interpolation' but for masks.
            Default: 0 (Nearest-neighbor).
        cval (number): The constant value to use when filling in newly created pixels.
            Default: 0.
        cval_mask (number): The constant value to use when filling in newly created pixels in masks.
            Default: 0.
        mode (str): {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional
            Points outside the boundaries of the input are filled according
            to the given mode. Default: 'constant'.
        absolute_scale (bool): If set to True, the value of the scale parameter will be treated as an absolute
            pixel value. If set to False, it will be treated as a fraction of the image height and width.
            Default: False.
        keypoints_threshold (float): Used as threshold in conversion from distance maps to keypoints.
            The search for keypoints works by searching for the argmin (non-inverted) or argmax (inverted) in each
            channel. This parameter contains the maximum (non-inverted) or minimum (inverted) value to accept in order
            to view a hit as a keypoint. Use None to use no min/max. Default: 0.01.
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, keypoints, bboxes

    Image types:
        uint8, float32

    Note:
        - This augmentation is very slow. Consider using `ElasticTransform` instead, which is at least 10x faster.
        - The augmentation may not always produce visible effects, especially with small scale values.
        - For keypoints and bounding boxes, the transformation might move them outside the image boundaries.
          In such cases, the keypoints will be set to (-1, -1) and the bounding boxes will be removed.

    Example:
        >>> import numpy as np
        >>> import albumentations as A
        >>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
        >>> transform = A.Compose([
        ...     A.PiecewiseAffine(scale=(0.03, 0.05), nb_rows=4, nb_cols=4, p=0.5),
        ... ])
        >>> transformed = transform(image=image)
        >>> transformed_image = transformed["image"]
    c                   @  s~   e Zd ZU ded< ded< ded< ded< ded< d	ed
< d	ed< ded< ded< ded< eddeddddddZdS )zPiecewiseAffine.InitSchemar   r   r"   nb_rowsnb_colsr   r7   r   rE   r   r   =Literal[('constant', 'edge', 'symmetric', 'reflect', 'wrap')]r   ry   absolute_scalerG   keypoints_thresholdr!   r   tuple[float, float]r   c                 C  s*   dt f}t||}t|f||jf  |S )Nrc   )r   r%   r   r   r   rA   rA   rB   process_range  s    
z(PiecewiseAffine.InitSchema.process_rangeN)r=   r>   r?   r@   r   r   r   rA   rA   rA   rB   rC     s   
rC   )gQ?r   )   r   r   ZconstantFNg{Gz?rD   r!   r"   rE   r   ry   rF   rG   )r   r   r   r7   r   r   r   r   r   rI   r   rJ   c                   s   t  j||
d tddd ttttf || _ttttf || _ttttf || _	|| _
|| _|| _|| _|| _|	| _|| _d S )NrL   zhThis augmenter is very slow. Try to use ``ElasticTransformation`` instead, which is at least 10x faster.rc   r   )rM   rN   r   r   r   rG   r   rE   r   r   r7   r   r   r   r   r   r   )rO   r   r   r   r7   r   r   r   r   r   rI   r   rJ   rP   rA   rB   rN     s    zPiecewiseAffine.__init__rj   rk   c                 C  s   dS )N)
r   r   r   r7   r   r   r   r   r   r   rA   rl   rA   rA   rB   rm   1  s    z-PiecewiseAffine.get_transform_init_args_namesr~   r   c                 C  s  |d d d \}}t tj| j dd }t tj| j dd }|| }tj| j }t	d||df}	t 
|	dkstdD ](}
t	d||df}	t 
|	dkr| qq|t 
|	dksdd iS t d||}t d||}t ||\}}t |j|jgd }| jrb|dkr$|	d d df | nd|	d d df< |dkrR|	d d df | nd|	d d df< |	d d df | |	d d df< |	d d df | |	d d df< t |}|d d df |	d d df  |d d df< |d d df |	d d df  |d d df< t |d d df d|d |d d df< t |d d df d|d |d d df< tj }||d d d d df |d d d d df  d|iS )	Nrb   rc   r   r   r   r   r&   r   )r   Zclipr   r   r   r   r   r   r   normalanyrangeZlinspacer   ZdstackZflatr   copyskimageZ	transformZPiecewiseAffineTransformZestimate)rO   rV   r   r   r   r   r   Znb_cellsr   jitterr   r   r   Zxx_srcZyy_srcZ
points_srcZpoints_destr   rA   rA   rB   r   ?  s@    ..  
,,**
0 z,PiecewiseAffine.get_params_dependent_on_datarR   z*skimage.transform.PiecewiseAffineTransformr   )rS   r   rV   rW   c                 K  s   t ||| j| j| jS rX   )rY   piecewise_affiner7   r   r   )rO   rS   r   rV   rA   rA   rB   r[   r  s    zPiecewiseAffine.apply)r\   r   rV   rW   c                 K  s   t ||| j| j| jS rX   )rY   r  r   r   r   )rO   r\   r   rV   rA   rA   rB   r_   z  s    zPiecewiseAffine.apply_to_mask)r`   r   rV   rW   c                 K  s   t |||d | jS rh   )rY   Zbboxes_piecewise_affiner   )rO   r`   r   rV   rA   rA   rB   rf     s    zPiecewiseAffine.apply_to_bboxes)rg   r   rV   rW   c                 K  s   t |||d | jS rh   )rY   Zkeypoints_piecewise_affiner   )rO   rg   r   rV   rA   rA   rB   ri     s    z"PiecewiseAffine.apply_to_keypoints)r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r   rC   r]   rt   r^   rN   rm   r   r[   r_   rf   ri   rv   rA   rA   rP   rB   r,     s,   E*!3c                      s  e Zd ZdZejejejejfZ	G dd de
Zdddddejddddf
ddddd	d
ddddd
 fddZdddd fddZdd
d
d
d
dddddZdd
d
d
d
dddddZdd
d
d
d
dddddZdd
d
d
d
ddd d!d"Zd#d$d%d&Zd
d
d
d
d'd(d)d*Z  ZS )+r3   a
  Pads the sides of an image if the image dimensions are less than the specified minimum dimensions.
    If the `pad_height_divisor` or `pad_width_divisor` is specified, the function additionally ensures
    that the image dimensions are divisible by these values.

    Args:
        min_height (int | None): Minimum desired height of the image. Ensures image height is at least this value.
            If not specified, pad_height_divisor must be provided.
        min_width (int | None): Minimum desired width of the image. Ensures image width is at least this value.
            If not specified, pad_width_divisor must be provided.
        pad_height_divisor (int | None): If set, pads the image height to make it divisible by this value.
            If not specified, min_height must be provided.
        pad_width_divisor (int | None): If set, pads the image width to make it divisible by this value.
            If not specified, min_width must be provided.
        position (Literal["center", "top_left", "top_right", "bottom_left", "bottom_right", "random"]):
            Position where the image is to be placed after padding. Default is 'center'.
        border_mode (int): Specifies the border mode to use if padding is required.
            The default is `cv2.BORDER_REFLECT_101`.
        value (int, float, list[int], list[float] | None): Value to fill the border pixels if
            the border mode is `cv2.BORDER_CONSTANT`. Default is None.
        mask_value (int, float, list[int], list[float] | None): Similar to `value` but used for padding masks.
            Default is None.
        p (float): Probability of applying the transform. Default is 1.0.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - Either `min_height` or `pad_height_divisor` must be set, but not both.
        - Either `min_width` or `pad_width_divisor` must be set, but not both.
        - If `border_mode` is set to `cv2.BORDER_CONSTANT`, `value` must be provided.
        - The transform will maintain consistency across all targets (image, mask, bboxes, keypoints).
        - For bounding boxes, the coordinates will be adjusted to account for the padding.
        - For keypoints, their positions will be shifted according to the padding.

    Example:
        >>> import albumentations as A
        >>> transform = A.Compose([
        ...     A.PadIfNeeded(min_height=1024, min_width=1024, border_mode=cv2.BORDER_CONSTANT, value=0),
        ... ])
        >>> transformed = transform(image=image, mask=mask, bboxes=bboxes, keypoints=keypoints)
        >>> padded_image = transformed['image']
        >>> padded_mask = transformed['mask']
        >>> adjusted_bboxes = transformed['bboxes']
        >>> adjusted_keypoints = transformed['keypoints']
    c                   @  s   e Zd ZU eddZded< eddZded< eddZded< eddZded< ded	< d
ed< ded< ded< e	ddddddZ
dS )zPadIfNeeded.InitSchemar&   )ge
int | None
min_height	min_widthpad_height_divisorpad_width_divisorr   positionr   r8   r9   r:   r;   r   r   r   rk   c                 C  sf   | j d k| jd kkr d}t|| jd k| jd kkr@d}t|| jtjkrb| jd krbd}t|| S )NzHOnly one of 'min_height' and 'pad_height_divisor' parameters must be setzFOnly one of 'min_width' and 'pad_width_divisor' parameters must be setzGIf 'border_mode' is set to 'BORDER_CONSTANT', 'value' must be provided.)	r	  r  r   r
  r  r8   r]   r   r:   )rO   r   rA   rA   rB   validate_divisibility  s    z,PadIfNeeded.InitSchema.validate_divisibilityN)r=   r>   r?   r   r	  r@   r
  r  r  r   r  rA   rA   rA   rB   rC     s   
rC   i   Nr   r   r  r   rE   r9   rF   rG   )
r	  r
  r  r  r  r8   r:   r;   rI   rJ   c                   sD   t  j|
|	d || _|| _|| _|| _|| _|| _|| _|| _	d S rK   )
rM   rN   r	  r
  r  r  r  r8   r:   r;   )rO   r	  r
  r  r  r  r8   r:   r;   rI   rJ   rP   rA   rB   rN     s    zPadIfNeeded.__init__r~   r   )rV   kwargsrW   c                   s6  t  j|f|}|d d d \}}| jd k	rd|| jk rZt| j| d }| j| | }qd}d}n0|| j }|dkr| j| nd}|d }|| }| jd k	r|| jk rt| j| d }	| j| |	 }
nd}	d}
n0|| j }|dkr| j| nd}|d }	||	 }
| j|||	|
d\}}}	}
||||	|
d |S )Nrb   rc   g       @r   )h_toph_bottomw_leftw_right)pad_top
pad_bottompad_left	pad_right)	rM   update_paramsr	  rE   r  r
  r  $_PadIfNeeded__update_position_paramsupdate)rO   rV   r  rowscolsZ	h_pad_topZh_pad_bottomZpad_remainedZpad_rowsZ
w_pad_leftZw_pad_rightZpad_remainderZpad_colsrP   rA   rB   r    sH    





zPadIfNeeded.update_paramsrR   )rS   r  r  r  r  rV   rW   c              	   K  s   t j|||||| j| jdS N)r8   r:   )rY   pad_with_paramsr8   r:   )rO   rS   r  r  r  r  rV   rA   rA   rB   r[   (  s    	zPadIfNeeded.apply)r\   r  r  r  r  rV   rW   c              	   K  s   t j|||||| j| jdS r  )rY   r  r8   r;   )rO   r\   r  r  r  r  rV   rA   rA   rB   r_   ;  s    	zPadIfNeeded.apply_to_mask)r`   r  r  r  r  rV   rW   c              	   K  sj   |d d d }t ||d }tj|||||| j|d}	|d d d \}
}t|	|
| | || | fS Nrb   rc   )rd   )r   rY   Z
pad_bboxesr8   r   )rO   r`   r  r  r  r  rV   rd   Z	bboxes_npr   r  r  rA   rA   rB   rf   N  s    	
zPadIfNeeded.apply_to_bboxes)rg   r  r  r  r  rV   rW   c              
   K  s&   t j|||||| j|d d d dS r  )rY   Zpad_keypointsr8   )rO   rg   r  r  r  r  rV   rA   rA   rB   ri   h  s    	zPadIfNeeded.apply_to_keypointsrj   rk   c                 C  s   dS )N)r	  r
  r  r  r  r8   r:   r;   rA   rl   rA   rA   rB   rm   {  s    z)PadIfNeeded.get_transform_init_args_namesztuple[int, int, int, int])r  r  r  r  rW   c                 C  s   | j dkr$||7 }||7 }d}d}n| j dkrH||7 }||7 }d}d}n| j dkrl||7 }||7 }d}d}nf| j dkr||7 }||7 }d}d}nB| j dkr|| }|| }td|}|| }td|}|| }||||fS )NZtop_leftr   Z	top_rightZbottom_leftZbottom_rightr   )r  r   r   )rO   r  r  r  r  Zh_padZw_padrA   rA   rB   Z__update_position_params  s8    




z$PadIfNeeded.__update_position_params)r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r   rC   r]   ru   rN   r  r[   r_   rf   ri   rm   r  rv   rA   rA   rP   rB   r3     s*   1&1c                   @  sh   e Zd ZdZejejejejf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ZdS )r-   ag  Flip the input vertically around the x-axis.

    Args:
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - This transform flips the image upside down. The top of the image becomes the bottom and vice versa.
        - The dimensions of the image remain unchanged.
        - For multi-channel images (like RGB), each channel is flipped independently.
        - Bounding boxes are adjusted to match their new positions in the flipped image.
        - Keypoints are moved to their new positions in the flipped image.

    Mathematical Details:
        1. For an input image I of shape (H, W, C), the output O is:
           O[i, j, k] = I[H-1-i, j, k] for all i in [0, H-1], j in [0, W-1], k in [0, C-1]
        2. For bounding boxes with coordinates (x_min, y_min, x_max, y_max):
           new_bbox = (x_min, H-y_max, x_max, H-y_min)
        3. For keypoints with coordinates (x, y):
           new_keypoint = (x, H-y)
        where H is the height of the image.

    Example:
        >>> import numpy as np
        >>> import albumentations as A
        >>> image = np.array([
        ...     [[1, 2, 3], [4, 5, 6]],
        ...     [[7, 8, 9], [10, 11, 12]]
        ... ])
        >>> transform = A.VerticalFlip(p=1.0)
        >>> result = transform(image=image)
        >>> flipped_image = result['image']
        >>> print(flipped_image)
        [[[ 7  8  9]
          [10 11 12]]
         [[ 1  2  3]
          [ 4  5  6]]]
        # The original image is flipped vertically, with rows reversed

    rR   r   rS   rV   rW   c                 K  s   t |S rX   )r	   rO   rS   rV   rA   rA   rB   r[     s    zVerticalFlip.applyr`   rV   rW   c                 K  s
   t |S rX   )rY   Zbboxes_vfliprO   r`   rV   rA   rA   rB   rf     s    zVerticalFlip.apply_to_bboxesrg   rV   rW   c                 K  s   t ||d S )Nr  )rY   Zkeypoints_vfliprO   rg   rV   rA   rA   rB   ri     s    zVerticalFlip.apply_to_keypoints	tuple[()]rk   c                 C  s   dS NrA   rA   rl   rA   rA   rB   rm     s    z*VerticalFlip.get_transform_init_args_namesNr=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r[   rf   ri   rm   rA   rA   rA   rB   r-     s   .c                   @  sh   e Zd ZdZejejejejf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ZdS )r.   zFlip the input horizontally around the y-axis.

    Args:
        p (float): probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    rR   r   r   c                 K  s   t |S rX   )r   r!  rA   rA   rB   r[     s    zHorizontalFlip.applyr"  c                 K  s
   t |S rX   )rY   Zbboxes_hflipr#  rA   rA   rB   rf     s    zHorizontalFlip.apply_to_bboxesr$  c                 K  s   t ||d S )Nr  )rY   Zkeypoints_hflipr%  rA   rA   rB   ri     s    z!HorizontalFlip.apply_to_keypointsr&  rk   c                 C  s   dS r'  rA   rl   rA   rA   rB   rm     s    z,HorizontalFlip.get_transform_init_args_namesNr(  rA   rA   rA   rB   r.     s   c                      s   e Zd ZdZejejejejfZ	dddd fddZ
d	d
dd	dddZddddZd	dd	dddZd	dd	dddZddddZ  ZS )r/   zNDeprecated. Consider using HorizontalFlip, VerticalFlip, RandomRotate90 or D4.NrD   rF   rG   rI   rJ   c                   s"   t  j||d tdtdd d S )NrL   zVFlip is deprecated. Consider using HorizontalFlip, VerticalFlip, RandomRotate90 or D4.rc   r   )rM   rN   r   r   rO   rI   rJ   rP   rA   rB   rN     s    zFlip.__init__rR   rE   r   )rS   drV   rW   c                 K  s   t ||S )a  Args:
        d (int): code that specifies how to flip the input. 0 for vertical flipping, 1 for horizontal flipping,
                -1 for both vertical and horizontal flipping (which is also could be seen as rotating the input by
                180 degrees).
        )rY   Zrandom_flip)rO   rS   r+  rV   rA   rA   rB   r[     s    z
Flip.applyzdict[str, int]rk   c                 C  s   dt ddiS )Nr+  r   r&   r   rl   rA   rA   rB   
get_params!  s    zFlip.get_paramsr"  c                 K  s   t ||d S )Nr+  )rY   Zbboxes_flipr#  rA   rA   rB   rf   %  s    zFlip.apply_to_bboxesr$  c                 K  s   t ||d |d S )Nr+  rb   )rY   Zkeypoints_flipr%  rA   rA   rB   ri   (  s    zFlip.apply_to_keypointsr&  c                 C  s   dS r'  rA   rl   rA   rA   rB   rm   +  s    z"Flip.get_transform_init_args_names)NrD   )r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   rN   r[   r,  rf   ri   rm   rv   rA   rA   rP   rB   r/     s   c                   @  sh   e Zd ZdZejejejejf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ZdS )r0   ax  Transpose the input by swapping its rows and columns.

    This transform flips the image over its main diagonal, effectively switching its width and height.
    It's equivalent to a 90-degree rotation followed by a horizontal flip.

    Args:
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - The dimensions of the output will be swapped compared to the input. For example,
          an input image of shape (100, 200, 3) will result in an output of shape (200, 100, 3).
        - This transform is its own inverse. Applying it twice will return the original input.
        - For multi-channel images (like RGB), the channels are preserved in their original order.
        - Bounding boxes will have their coordinates adjusted to match the new image dimensions.
        - Keypoints will have their x and y coordinates swapped.

    Mathematical Details:
        1. For an input image I of shape (H, W, C), the output O is:
           O[i, j, k] = I[j, i, k] for all i in [0, W-1], j in [0, H-1], k in [0, C-1]
        2. For bounding boxes with coordinates (x_min, y_min, x_max, y_max):
           new_bbox = (y_min, x_min, y_max, x_max)
        3. For keypoints with coordinates (x, y):
           new_keypoint = (y, x)

    Example:
        >>> import numpy as np
        >>> import albumentations as A
        >>> image = np.array([
        ...     [[1, 2, 3], [4, 5, 6]],
        ...     [[7, 8, 9], [10, 11, 12]]
        ... ])
        >>> transform = A.Transpose(p=1.0)
        >>> result = transform(image=image)
        >>> transposed_image = result['image']
        >>> print(transposed_image)
        [[[ 1  2  3]
          [ 7  8  9]]
         [[ 4  5  6]
          [10 11 12]]]
        # The original 2x2x3 image is now 2x2x3, with rows and columns swapped

    rR   r   r   c                 K  s
   t |S rX   )rY   Z	transposer!  rA   rA   rB   r[   c  s    zTranspose.applyr"  c                 K  s
   t |S rX   )rY   Zbboxes_transposer#  rA   rA   rB   rf   f  s    zTranspose.apply_to_bboxesr$  c                 K  s
   t |S rX   )rY   Zkeypoints_transposer%  rA   rA   rB   ri   i  s    zTranspose.apply_to_keypointsr&  rk   c                 C  s   dS r'  rA   rl   rA   rA   rB   rm   l  s    z'Transpose.get_transform_init_args_namesNr(  rA   rA   rA   rB   r0   /  s   1c                
      s   e Zd ZdZG dd dejZddejejddddfddddd	d	d
dd fddZ	ddddddZ
dd fddZ  ZS )r1   a
  Apply optical distortion to images, masks, bounding boxes, and keypoints.

    This transformation simulates lens distortion effects by warping the image using
    a camera matrix and distortion coefficients. It's particularly useful for
    augmenting data in computer vision tasks where camera lens effects are relevant.

    Args:
        distort_limit (float or tuple of float): Range of distortion coefficient.
            If distort_limit is a single float, the range will be (-distort_limit, distort_limit).
            Default: (-0.05, 0.05).
        shift_limit (float or tuple of float): Range of shifts for the image center.
            If shift_limit is a single float, the range will be (-shift_limit, shift_limit).
            Default: (-0.05, 0.05).
        interpolation (OpenCV flag): Interpolation method used for image transformation.
            Should be one of: cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC,
            cv2.INTER_AREA, cv2.INTER_LANCZOS4. Default: cv2.INTER_LINEAR.
        border_mode (OpenCV flag): Border mode used for handling pixels outside the image.
            Should be one of: cv2.BORDER_CONSTANT, cv2.BORDER_REPLICATE, cv2.BORDER_REFLECT,
            cv2.BORDER_WRAP, cv2.BORDER_REFLECT_101. Default: cv2.BORDER_REFLECT_101.
        value (int, float, list of int, list of float): Padding value if border_mode
            is cv2.BORDER_CONSTANT. Default: None.
        mask_value (int, float, list of int, list of float): Padding value for mask
            if border_mode is cv2.BORDER_CONSTANT. Default: None.
        always_apply (bool): If True, the transform will be always applied.
            Default: None.
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - The distortion is applied using OpenCV's initUndistortRectifyMap and remap functions.
        - The distortion coefficient (k) is randomly sampled from the distort_limit range.
        - The image center is shifted by dx and dy, randomly sampled from the shift_limit range.
        - Bounding boxes and keypoints are transformed along with the image to maintain consistency.

    Example:
        >>> import albumentations as A
        >>> transform = A.Compose([
        ...     A.OpticalDistortion(distort_limit=0.1, shift_limit=0.1, p=1.0),
        ... ])
        >>> transformed = transform(image=image, mask=mask, bboxes=bboxes, keypoints=keypoints)
        >>> transformed_image = transformed['image']
        >>> transformed_mask = transformed['mask']
        >>> transformed_bboxes = transformed['bboxes']
        >>> transformed_keypoints = transformed['keypoints']
    c                   @  s   e Zd ZU ded< ded< dS )zOpticalDistortion.InitSchemar   distort_limitr   Nr<   rA   rA   rA   rB   rC     s   
rC   )gr   NrD   r!   rE   r9   rF   rG   )r-  r   r7   r8   r:   r;   rI   rJ   c	           	        sD   t  j||||||d ttttf || _ttttf || _d S r}   )rM   rN   r   r   rG   r   r-  )	rO   r-  r   r7   r8   r:   r;   rI   rJ   rP   rA   rB   rN     s    zOpticalDistortion.__init__r~   r   c                 C  s   |d d d \}}|}|}t j| j }tt j| j }tt j| j }	|d | }
|d |	 }tj|d|
gd||gdddggtjd}tj||dddgtjd}t	||d d ||ftj
\}}||dS )Nrb   rc   rD   r   r&   )Zdtyper   )r   r   r-  roundr   r   arrayr   r]   ZinitUndistortRectifyMapZCV_32FC1)rO   rV   r   r   r   ZfxZfykr   r   ZcxcyZcamera_matrixrZ   rT   rU   rA   rA   rB   r     s    (z.OpticalDistortion.get_params_dependent_on_datarj   rk   c                   s   t   dS )Nr-  r   )r-  r   r   rl   rP   rA   rB   rm     s    z/OpticalDistortion.get_transform_init_args_namesr   rA   rA   rP   rB   r1   p  s   3"c                      s   e Zd ZdZG dd dejZddejejdddddf	d	d
d	d	dddddd	 fddZ	ddddddZ
dd fddZ  ZS )r2   a
  Apply grid distortion to images, masks, bounding boxes, and keypoints.

    This transformation divides the image into a grid and randomly distorts each cell,
    creating localized warping effects. It's particularly useful for data augmentation
    in tasks like medical image analysis, OCR, and other domains where local geometric
    variations are meaningful.

    Args:
        num_steps (int): Number of grid cells on each side of the image. Higher values
            create more granular distortions. Must be at least 1. Default: 5.
        distort_limit (float or tuple[float, float]): Range of distortion. If a single float
            is provided, the range will be (-distort_limit, distort_limit). Higher values
            create stronger distortions. Should be in the range of -1 to 1.
            Default: (-0.3, 0.3).
        interpolation (int): OpenCV interpolation method used for image transformation.
            Options include cv2.INTER_LINEAR, cv2.INTER_CUBIC, etc. Default: cv2.INTER_LINEAR.
        border_mode (int): OpenCV border mode used for handling pixels outside the image.
            Options include cv2.BORDER_REFLECT_101, cv2.BORDER_CONSTANT, etc.
            Default: cv2.BORDER_REFLECT_101.
        value (int, float, list of int, list of float, optional): Padding value if
            border_mode is cv2.BORDER_CONSTANT. Default: None.
        mask_value (int, float, list of int, list of float, optional): Padding value for
            mask if border_mode is cv2.BORDER_CONSTANT. Default: None.
        normalized (bool): If True, ensures that the distortion does not move pixels
            outside the image boundaries. This can result in less extreme distortions
            but guarantees that no information is lost. Default: True.
        always_apply (bool): If True, the transform will be always applied. Default: None.
        p (float): Probability of applying the transform. Default: 0.5.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - The same distortion is applied to all targets (image, mask, bboxes, keypoints)
          to maintain consistency.
        - When normalized=True, the distortion is adjusted to ensure all pixels remain
          within the image boundaries.

    Example:
        >>> import albumentations as A
        >>> transform = A.Compose([
        ...     A.GridDistortion(num_steps=5, distort_limit=0.3, p=1.0),
        ... ])
        >>> transformed = transform(image=image, mask=mask, bboxes=bboxes, keypoints=keypoints)
        >>> transformed_image = transformed['image']
        >>> transformed_mask = transformed['mask']
        >>> transformed_bboxes = transformed['bboxes']
        >>> transformed_keypoints = transformed['keypoints']

    c                   @  sD   e Zd ZU ded< ded< ded< ededddd	d
dZdS )zGridDistortion.InitSchemazAnnotated[int, Field(ge=1)]	num_stepsr   r-  ry   
normalizedr   r   )vr   rW   c                 C  s$   d}t |}t|f||jf  |S )Nr   )r%   r   r   )r   r4  r   r   r   rA   rA   rB   check_limits  s    z&GridDistortion.InitSchema.check_limitsN)r=   r>   r?   r@   r   r   r5  rA   rA   rA   rB   rC     s   
rC      )g333333ӿg333333?NTrD   rE   r!   r9   ry   rF   rG   )	r2  r-  r7   r8   r:   r;   r3  rI   rJ   c
           
        s<   t  j||||||	d || _ttttf || _|| _d S r}   )rM   rN   r2  r   r   rG   r-  r3  )
rO   r2  r-  r7   r8   r:   r;   r3  rI   rJ   rP   rA   rB   rN     s    zGridDistortion.__init__r~   r   c           	        s   |d d d } fddt  jd D } fddt  jd D } jrrt| j||}|d |d  }}t||| j\}}||d	S )
Nrb   rc   c                   s   g | ]}d t j j  qS r&   r   r   r-  r   r   rl   rA   rB   
<listcomp>3  s     z?GridDistortion.get_params_dependent_on_data.<locals>.<listcomp>r&   c                   s   g | ]}d t j j  qS r7  r8  r9  rl   rA   rB   r:  4  s     steps_xsteps_yr   )r  r2  r3  rY   Znormalize_grid_distortion_stepsZgenerate_grid)	rO   rV   r   rd   r;  r<  Znormalized_paramsrT   rU   rA   rl   rB   r   1  s    z+GridDistortion.get_params_dependent_on_datarj   rk   c                   s   t   dS )Nr2  r-  r3  )r2  r-  r3  r   rl   rP   rA   rB   rm   C  s    z,GridDistortion.get_transform_init_args_namesr   rA   rA   rP   rB   r2     s   6$c                      s   e Zd ZdZejejejejfZ	G dd de
Zdddd fd	d
ZdddddddZdddddddZdddddddZddddZddddZ  ZS )r4   a  Applies one of the eight possible D4 dihedral group transformations to a square-shaped input,
    maintaining the square shape. These transformations correspond to the symmetries of a square,
    including rotations and reflections.

    The D4 group transformations include:
    - 'e' (identity): No transformation is applied.
    - 'r90' (rotation by 90 degrees counterclockwise)
    - 'r180' (rotation by 180 degrees)
    - 'r270' (rotation by 270 degrees counterclockwise)
    - 'v' (reflection across the vertical midline)
    - 'hvt' (reflection across the anti-diagonal)
    - 'h' (reflection across the horizontal midline)
    - 't' (reflection across the main diagonal)

    Even if the probability (`p`) of applying the transform is set to 1, the identity transformation
    'e' may still occur, which means the input will remain unchanged in one out of eight cases.

    Args:
        p (float): Probability of applying the transform. Default: 1.0.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Note:
        - This transform is particularly useful for augmenting data that does not have a clear orientation,
          such as top-view satellite or drone imagery, or certain types of medical images.
        - The input image should be square-shaped for optimal results. Non-square inputs may lead to
          unexpected behavior or distortions.
        - When applied to bounding boxes or keypoints, their coordinates will be adjusted according
          to the selected transformation.
        - This transform preserves the aspect ratio and size of the input.

    Example:
        >>> import numpy as np
        >>> import albumentations as A
        >>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
        >>> transform = A.Compose([
        ...     A.D4(p=1.0),
        ... ])
        >>> transformed = transform(image=image)
        >>> transformed_image = transformed['image']
        # The resulting image will be one of the 8 possible D4 transformations of the input
    c                   @  s   e Zd ZdS )zD4.InitSchemaN)r=   r>   r?   rA   rA   rA   rB   rC   y  s   rC   Nr&   rF   rG   r)  c                   s   t  j||d d S rK   )rM   rN   r*  rP   rA   rB   rN   |  s    zD4.__init__rR   r   r   )rS   group_elementrV   rW   c                 K  s   t ||S rX   )rY   Zd4)rO   rS   r=  rV   rA   rA   rB   r[     s    zD4.apply)r`   r=  rV   rW   c                 K  s   t ||S rX   )rY   Z	bboxes_d4)rO   r`   r=  rV   rA   rA   rB   rf     s    zD4.apply_to_bboxes)rg   r=  rV   rW   c                 K  s   t |||d S rh   )rY   Zkeypoints_d4)rO   rg   r=  rV   rA   rA   rB   ri     s    zD4.apply_to_keypointszdict[str, D4Type]rk   c                 C  s   dt tiS )Nr=  )r   r   r$   rl   rA   rA   rB   r,    s     zD4.get_paramsr&  c                 C  s   dS r'  rA   rl   rA   rA   rB   rm     s    z D4.get_transform_init_args_names)Nr&   )r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r   rC   rN   r[   rf   ri   r,  rm   rv   rA   rA   rP   rB   r4   G  s   /  c                      s   e Zd ZdZejejejejfZ	G dd de
Zejejddfdddddd	d
 fddZeddddddZddddddZdddddddZdddddddZdddddddZdddddd d!Zd"d#d$d%Z  ZS )&r5   a  Apply elastic deformations to images, masks, bounding boxes, and keypoints using a grid-based approach.

    This transformation overlays a grid on the input and applies random displacements to the grid points,
    resulting in local elastic distortions. The granularity and intensity of the distortions can be
    controlled using the dimensions of the overlaying distortion grid and the magnitude parameter.


    Args:
        num_grid_xy (tuple[int, int]): Number of grid cells along the width and height.
            Specified as (grid_width, grid_height). Each value must be greater than 1.
        magnitude (int): Maximum pixel-wise displacement for distortion. Must be greater than 0.
        interpolation (int): Interpolation method to be used for the image transformation.
            Default: cv2.INTER_LINEAR
        mask_interpolation (int): Interpolation method to be used for mask transformation.
            Default: cv2.INTER_NEAREST
        p (float): Probability of applying the transform. Default: 1.0.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32

    Example:
        >>> transform = GridElasticDeform(num_grid_xy=(4, 4), magnitude=10, p=1.0)
        >>> result = transform(image=image, mask=mask)
        >>> transformed_image, transformed_mask = result['image'], result['mask']

    Note:
        This transformation is particularly useful for data augmentation in medical imaging
        and other domains where elastic deformations can simulate realistic variations.
    c                   @  s8   e Zd ZU ded< eddZded< ded< ded	< d
S )zGridElasticDeform.InitSchemaz7Annotated[tuple[int, int], AfterValidator(check_1plus)]num_grid_xyr   )gtrE   	magnituder   r7   r   N)r=   r>   r?   r@   r   r@  rA   rA   rA   rB   rC     s   
rC   r   Nr   rE   rG   rF   )r>  r@  r7   r   rJ   rI   c                   s,   t  j||d || _|| _|| _|| _d S rK   )rM   rN   r>  r@  r7   r   )rO   r>  r@  r7   r   rJ   rI   rP   rA   rB   rN     s
    	zGridElasticDeform.__init__rR   )polygons
dimensionsrW   c                 C  s   t |dd| fS )Nr   r   )r   Zhstackreshape)rA  rB  rA   rA   rB   generate_mesh  s    zGridElasticDeform.generate_meshr~   r   c                 C  sj   |d d d }t || j}tdd |D | jd d d d }t || j}| ||}d|iS )Nrb   rc   c                 S  s(   g | ] }|d  |d |d |d gqS )r&   r      rc   rA   )r   ZtilerA   rA   rB   r:    s   zBGridElasticDeform.get_params_dependent_on_data.<locals>.<listcomp>r   )r   generated_mesh)	rY   Zsplit_uniform_gridr>  r   r/  rC  Z generate_distorted_grid_polygonsr@  rD  )rO   rV   r   rd   ZtilesrB  rA  rF  rA   rA   rB   r     s    z.GridElasticDeform.get_params_dependent_on_datar   )rS   rF  rV   rW   c                 K  s   t ||| jS rX   )rY   distort_imager7   )rO   rS   rF  rV   rA   rA   rB   r[     s    zGridElasticDeform.apply)r\   rF  rV   rW   c                 K  s   t ||| jS rX   )rY   rG  r   )rO   r\   rF  rV   rA   rA   rB   r_     s    zGridElasticDeform.apply_to_mask)r`   rF  rV   rW   c                 K  sB   t ||d d d }tt|||d d d |d d d S ra   )r   r   rY   Zbbox_distort_image)rO   r`   rF  rV   re   rA   rA   rB   rf     s    z!GridElasticDeform.apply_to_bboxes)rg   rF  rV   rW   c                 K  s   t |||d d d S ra   )rY   Zdistort_image_keypoints)rO   rg   rF  rV   rA   rA   rB   ri     s    z$GridElasticDeform.apply_to_keypointsrj   rk   c                 C  s   dS )N)r>  r@  r7   r   rA   rl   rA   rA   rB   rm     s    z/GridElasticDeform.get_transform_init_args_names)r=   r>   r?   rn   r#   ro   rp   rq   rr   rs   r   rC   r]   rt   r^   rN   r   rD  r   r[   r_   rf   ri   rm   rv   rA   rA   rP   rB   r5     s    !
)J
__future__r   r   typingr   r   r   r   warningsr   r]   Znumpyr   Zskimage.transformr  Zalbucorer   r	   Zpydanticr
   r   r   r   r   Ztyping_extensionsr   r   Zalbumentationsr   Z"albumentations.augmentations.utilsr   Zalbumentations.core.bbox_utilsr   r   Zalbumentations.core.pydanticr   r   r   r   r   Z(albumentations.core.transforms_interfacer   r   Zalbumentations.core.typesr   r   r   r   r    r!   r"   r#   r$   Zalbumentations.core.utilsr%    r'   rY   __all__r6   r)   r*   r+   r(   r,   r3   r-   r.   r/   r0   r1   r2   r4   r5   rA   rA   rA   rB   <module>   sl   ,_r 0  x  `   >#AerS