
    hJ                       S r SSKJr  SSKrSSKJr  SSKJrJr  SSK	r
SSKJr  SSKJrJrJr  / S	Qr1 S
krSS jr " S S\5      r " S S\5      rSS jr        SS jr  S           SS jjr  S           SS jjrg)a  Module for handling keypoint operations during augmentation.

This module provides utilities for working with keypoints in various formats during
the augmentation process. It includes functions for converting between coordinate systems,
filtering keypoints based on visibility, validating keypoint data, and applying
transformations to keypoints. The module supports different keypoint formats including
xy, yx, and those with additional angle or size information.
    )annotationsN)Sequence)AnyLiteral)'NUM_KEYPOINTS_COLUMNS_IN_ALBUMENTATIONS   )DataProcessorParams	ShapeType)KeypointParamsKeypointsProcessorangle_to_2pi_rangecheck_keypoints%convert_keypoints_from_albumentations#convert_keypoints_to_albumentationsfilter_keypoints>   xyyxxyaxysxyzxyasxysac                R    [         R                  " U S[         R                  -  5      $ )uJ  Convert angles to the range [0, 2π).

This function takes an array of angles and ensures they are all within
the range of 0 to 2π (exclusive) by applying modulo 2π.

Args:
    angles (np.ndarray): Array of angle values in radians.

Returns:
    np.ndarray: Array of the same shape as input with angles normalized to [0, 2π).

   )npmodpi)angless    ]/var/www/fran/franai/venv/lib/python3.13/site-packages/albumentations/core/keypoints_utils.pyr   r   #   s     66&!bee)$$    c                     ^  \ rS rSrSr    S	         S
U 4S jjjrSU 4S jjr\SS j5       r\SS j5       r	SS jr
SrU =r$ )r   3   a  Parameters of keypoints

Args:
    format (str): format of keypoints. Should be 'xy', 'yx', 'xya', 'xys', 'xyas', 'xysa', 'xyz'.

        x - X coordinate,

        y - Y coordinate

        z - Z coordinate (for 3D keypoints)

        s - Keypoint scale

        a - Keypoint orientation in radians or degrees (depending on KeypointParams.angle_in_degrees)

    label_fields (list[str]): list of fields that are joined with keypoints, e.g labels.
        Should be same type as keypoints.
    remove_invisible (bool): to remove invisible points after transform or not
    angle_in_degrees (bool): angle in degrees or radians in 'xya', 'xyas', 'xysa' keypoints
    check_each_transform (bool): if `True`, then keypoints will be checked after each dual transform.
        Default: `True`

Note:
    The internal Albumentations format is [x, y, z, angle, scale]. For 2D formats (xy, yx, xya, xys, xyas, xysa),
    z coordinate is set to 0. For formats without angle or scale, these values are set to 0.

c                H   > [         TU ]  X5        X0l        X@l        XPl        g N)super__init__remove_invisibleangle_in_degreescheck_each_transform)selfformatlabel_fieldsr(   r)   r*   	__class__s         r    r'   KeypointParams.__init__P   s$     	. 0 0$8!r!   c                   > [         TU ]  5       nUR                  U R                  U R                  U R
                  S.5        U$ )zGet the private dictionary representation of keypoint parameters.

Returns:
    dict[str, Any]: Dictionary containing the keypoint parameters.

)r(   r)   r*   )r&   to_dict_privateupdater(   r)   r*   )r+   datar.   s     r    r1   KeypointParams.to_dict_private]   sE     w&($($9$9$($9$9(,(A(A	
 r!   c                    g)zCheck if the keypoint parameters are serializable.

Returns:
    bool: Always returns True as KeypointParams is serializable.

T clss    r    is_serializableKeypointParams.is_serializablen   s     r!   c                    g)zQGet the full name of the class.

Returns:
    str: The string "KeypointParams".

r   r6   r7   s    r    get_class_fullname!KeypointParams.get_class_fullnamex   s      r!   c                    SU R                    SU R                   SU R                   SU R                   SU R                   S3$ )NzKeypointParams(format=z, label_fields=z, remove_invisible=z, angle_in_degrees=z, check_each_transform=))r,   r-   r(   r)   r*   r+   s    r    __repr__KeypointParams.__repr__   sY    $T[[MARAR@S T!!%!6!6 77J4K`K`Ja b%%)%>%>$?qB	
r!   )r)   r*   r(   )NTTT)
r,   strr-   zSequence[str] | Noner(   boolr)   rD   r*   rD   )returndict[str, Any])rE   rD   rE   rC   )__name__
__module____qualname____firstlineno____doc__r'   r1   classmethodr9   r<   rA   __static_attributes____classcell__r.   s   @r    r   r   3   s    > .2!%!%%)99 +9 	9
 9 #9 9"      
 
r!   r   c                     ^  \ rS rSrSrSSU 4S jjjr\SS j5       rSS jr      SS jr	SS jr
      SS jr      SS	 jrS
rU =r$ )r      a  Processor for keypoint data transformation.

This class handles the conversion, validation, and filtering of keypoints
during transformations. It ensures keypoints are correctly formatted and
processed according to the specified keypoint parameters.

Args:
    params (KeypointParams): Parameters for keypoint processing.
    additional_targets (dict[str, str] | None): Dictionary mapping additional target names to their types.

c                $   > [         TU ]  X5        g r%   )r&   r'   )r+   paramsadditional_targetsr.   s      r    r'   KeypointsProcessor.__init__   s    4r!   c                    g)zTGet the default name for keypoint data.

Returns:
    str: The string "keypoints".

	keypointsr6   r@   s    r    default_data_name$KeypointsProcessor.default_data_name   s     r!   c                   ^ U R                   R                  (       a<  [        U4S jU R                   R                   5       5      (       d  Sn[        U5      egg)zEnsure the provided data dictionary contains all required label fields.

Args:
    data (dict[str, Any]): The data dictionary to validate.

Raises:
    ValueError: If any label field specified in params is missing from the data.

c              3  ,   >#    U  H	  oT;   v   M     g 7fr%   r6   ).0ir3   s     r    	<genexpr>7KeypointsProcessor.ensure_data_valid.<locals>.<genexpr>   s     /\C[aT	C[s   zaYour 'label_fields' are not valid - them must have same names as params in 'keypoint_params' dictN)rT   r-   all
ValueError)r+   r3   msgs    ` r    ensure_data_valid$KeypointsProcessor.ensure_data_valid   sD     ;;##C/\4;;C[C[/\,\,\uCS/! -]#r!   c                B    U   [        XU R                  R                  S9$ )a  Filter keypoints based on visibility within given shape.

Args:
    data (np.ndarray): Keypoints in [x, y, z, angle, scale] format
    shape (ShapeType): Shape to check against as {'height': height, 'width': width, 'depth': depth}

Returns:
    np.ndarray: Filtered keypoints

)r(   )r   rT   r(   r+   r3   shapes      r    filterKeypointsProcessor.filter   s     	dkk>Z>Z[[r!   c                    [        X5        g)zCheck if keypoints are valid within the given shape.

Args:
    data (np.ndarray): Keypoints to validate.
    shape (ShapeType): Shape to check against.

N)r   rg   s      r    checkKeypointsProcessor.check   s     	$r!   c                    UR                   (       d  U$ U R                  n[        UUR                  UUR                  UR
                  S9$ )a  Convert keypoints from internal Albumentations format to the specified format.

Args:
    data (np.ndarray): Keypoints in Albumentations format.
    shape (ShapeType): Shape information for validation.

Returns:
    np.ndarray: Converted keypoints in the target format.

check_validityr)   )sizerT   r   r,   r(   r)   r+   r3   rh   rT   s       r    convert_from_albumentations.KeypointsProcessor.convert_from_albumentations   sE     yyK4MM!22#44
 	
r!   c                    UR                   (       d  U$ U R                  n[        UUR                  UUR                  UR
                  S9$ )a  Convert keypoints from the specified format to internal Albumentations format.

Args:
    data (np.ndarray): Keypoints in source format.
    shape (ShapeType): Shape information for validation.

Returns:
    np.ndarray: Converted keypoints in Albumentations format.

ro   )rq   rT   r   r,   r(   r)   rr   s       r    convert_to_albumentations,KeypointsProcessor.convert_to_albumentations   sE     yyK2MM!22#44
 	
r!   r6   r%   )rT   r   rU   zdict[str, str] | NonerG   )r3   rF   rE   None)r3   
np.ndarrayrh   r   rE   ry   )r3   ry   rh   r   rE   rx   )rH   rI   rJ   rK   rL   r'   propertyrY   rd   ri   rl   rs   rv   rN   rO   rP   s   @r    r   r      s    
5 5  "\\ \ 
	\$%

 
 
	
6

 
 
	
 
r!   r   c           
       ^ ^^^ US   US   p2SU;   nT SS2S4   T SS2S4   pe[         R                  " US:  XS:  -  5      S   n[         R                  " US:  Xb:  -  5      S   n/ n	[        [        U5      [        U5      -  5       HM  n
X;   a  U	R	                  ST U
    SU S	XZ    35        X;   d  M.  U	R	                  S
T U
    SU S	Xj    35        MO     U(       a`  T R
                  S   S:  aM  T SS2S4   mUS   m[         R                  " TS:  TT:  -  5      S   nU	R                  UU U4S jU 5       5        T R
                  S   S:  aX  T SS2S4   m[         R                  " TS:  TS[        R                  -  :  -  5      S   nU	R                  UU 4S jU 5       5        U	(       a  [        SR                  U	5      5      eg)u  Check if keypoint coordinates are within valid ranges for the given shape.

This function validates that:
1. All x-coordinates are within [0, width)
2. All y-coordinates are within [0, height)
3. If depth is provided in shape, z-coordinates are within [0, depth)
4. Angles are within the range [0, 2π)

Args:
    keypoints (np.ndarray): Array of keypoints with shape (N, 5+), where N is the number of keypoints.
        - First 2 columns are always x, y
        - Column 3 (if present) is z
        - Column 4 (if present) is angle
        - Column 5+ (if present) are additional attributes
    shape (ShapeType): The shape of the image/volume:
                       - For 2D: {'height': int, 'width': int}
                       - For 3D: {'height': int, 'width': int, 'depth': int}

Raises:
    ValueError: If any keypoint coordinate is outside the valid range, or if angles are invalid.
               The error message will detail which keypoints are invalid and why.

Note:
    - The function assumes that keypoint coordinates are in absolute pixel values, not normalized
    - Angles are in radians
    - Z-coordinates are only checked if 'depth' is present in shape

heightwidthdepthNr   r   zExpected x for keypoint  to be in range [0, ), got zExpected y for keypoint r   c              3  F   >#    U  H  nS TU    ST STU    3v   M     g7f)zExpected z for keypoint r   r   Nr6   )r]   idxr~   rX   zs     r    r_   "check_keypoints.<locals>.<genexpr>;  s9      
mvfi&y~&66J5'QXYZ[^Y_X`amvs   !   c              3  @   >#    U  H  nS TU    STU    3v   M     g7f)zExpected angle for keypoint u    to be in range [0, 2π), got Nr6   )r]   r   r   rX   s     r    r_   r   C  s3      
% +9S>*::XY_`cYdXef%s   
)r   wheresortedsetappendrh   extendmathr   rb   join)rX   rh   r|   r}   	has_depthxy	invalid_x	invalid_yerror_messagesr   	invalid_zinvalid_anglesr   r~   r   s   `            @@@r    r   r     s   : (OU7^E5 I QT?IadOq!a%AJ/03I!a%AK01!4IN c)ns9~56!!*9S>*::NugU\]^]c\de !!*9S>*::NvhV]^_^d]ef 7 Y__Q'!+adOgHHa!eU
34Q7	 
mv
 	

 qA1a46A:&AK2G"HI!L 
%
 	

 >233 r!   c                    U(       d  U $ U R                   (       d  U $ US   US   UR                  SS5      pTnU SS2S4   U SS2S4   U SS2S4   pnUS:  Xd:  -  US:  -  Xs:  -  n	Ub  XS:  X:  -  -  n	X	   $ )a  Filter keypoints to remove those outside the boundaries.

Args:
    keypoints (np.ndarray): A numpy array of shape (N, 5+) where N is the number of keypoints.
                           Each row represents a keypoint (x, y, z, angle, scale, ...).
    shape (ShapeType): Shape to check against as {'height': height, 'width': width, 'depth': depth}.
    remove_invisible (bool): If True, remove keypoints outside the boundaries.

Returns:
    np.ndarray: Filtered keypoints.

r|   r}   r~   Nr   r   r   )rq   get)
rX   rh   r(   r|   r}   r~   r   r   r   visibles
             r    r   r   L  s    " >> ?E'NEIIgt<T5F 1oyA	!Q$!AAv!)$Q/1:>GFqy)) r!   c                |   U[         ;  a  [        SU S[          35      e/ SQ/ SQ/ SQ/ SQ/ SQ/ SQ/ S	QS
.nXQ   n[        R                  " U R                  S   [
        4[        R                  S9n[        U5       H  u  pU	c  M
  U SS2U	4   USS2U4'   M     U(       a*  US   b$  [        R                  " USS2S4   5      USS2S4'   [        USS2S4   5      USS2S4'   U R                  S   [        U5      :  a)  [        R                  " XpSS2[        U5      S24   45      nU(       a  [        Xr5        U$ )u;  Convert keypoints from various formats to the Albumentations format.

This function takes keypoints in different formats and converts them to the standard
Albumentations format: [x, y, z, angle, scale]. For 2D formats, z is set to 0.
For formats without angle or scale, these values are set to 0.

Args:
    keypoints (np.ndarray): Array of keypoints with shape (N, 2+), where N is the number of keypoints.
                            The number of columns depends on the source_format.
    source_format (Literal["xy", "yx", "xya", "xys", "xyas", "xysa", "xyz"]): The format of the input keypoints.
        - "xy": [x, y]
        - "yx": [y, x]
        - "xya": [x, y, angle]
        - "xys": [x, y, scale]
        - "xyas": [x, y, angle, scale]
        - "xysa": [x, y, scale, angle]
        - "xyz": [x, y, z]
    shape (ShapeType): The shape of the image {'height': height, 'width': width, 'depth': depth}.
    check_validity (bool, optional): If True, check if the converted keypoints are within the image boundaries.
                                     Defaults to False.
    angle_in_degrees (bool, optional): If True, convert input angles from degrees to radians.
                                       Defaults to True.

Returns:
    np.ndarray: Array of keypoints in Albumentations format [x, y, z, angle, scale] with shape (N, 5+).
                Any additional columns from the input keypoints are preserved and appended after the
                first 5 columns.

Raises:
    ValueError: If the source_format is not one of the supported formats.

Note:
    - For 2D formats (xy, yx, xya, xys, xyas, xysa), z coordinate is set to 0
    - Angles are converted to the range [0, 2π) radians
    - If the input keypoints have additional columns beyond what's specified in the source_format,
      these columns are preserved in the output

zUnknown source_format . Supported formats are: )r   r   NNN)r   r   NNN)r   r   Nr   N)r   r   NNr   )r   r   Nr   r   )r   r   Nr   r   )r   r   r   NNr   r   r   r   r   r   r   r   )dtypeNr   r   )keypoint_formatsrb   r   zerosrh   r   float32	enumerateradiansr   lencolumn_stackr   )
rX   source_formatrh   rp   r)   format_to_indicesindicesprocessed_keypointsr^   r   s
             r    r   r   p  sE   Z ,,1-@YZjYklmm '&$$""$6 !2 @G((IOOA$68_#`hjhrhrsG$?(1!S&(91% % GAJ2$&JJ/B1a4/H$IAqD! 23Fq!t3L M1qC.. oo/BaQTUbQcQeNeDf.gh+3r!   c           	        U[         ;  a  [        SU S[          35      eU SS2S4   U SS2S4   U SS2S4   U SS2S4   U SS2S4   4u  pVpxn	[        U5      nU(       a#  [        [        R
                  " XVXxU	45      U5        U(       a  [        R                  " U5      nXV/Xe/XVU/XVU	/XVX/XVX/XVU/S	.n
[        R
                  " X   5      nU R                  S   [        :  a$  [        R
                  " XSS2[        S24   45      $ U$ )
u  Convert keypoints from Albumentations format to various other formats.

This function takes keypoints in the standard Albumentations format [x, y, z, angle, scale]
and converts them to the specified target format.

Args:
    keypoints (np.ndarray): Array of keypoints in Albumentations format with shape (N, 5+),
                            where N is the number of keypoints. Each row represents a keypoint
                            [x, y, z, angle, scale, ...].
    target_format (Literal["xy", "yx", "xya", "xys", "xyas", "xysa", "xyz"]): The desired output format.
        - "xy": [x, y]
        - "yx": [y, x]
        - "xya": [x, y, angle]
        - "xys": [x, y, scale]
        - "xyas": [x, y, angle, scale]
        - "xysa": [x, y, scale, angle]
        - "xyz": [x, y, z]
    shape (ShapeType): The shape of the image {'height': height, 'width': width, 'depth': depth}.
    check_validity (bool, optional): If True, check if the keypoints are within the image boundaries.
                                     Defaults to False.
    angle_in_degrees (bool, optional): If True, convert output angles to degrees.
                                       If False, angles remain in radians.
                                       Defaults to True.

Returns:
    np.ndarray: Array of keypoints in the specified target format with shape (N, 2+).
                Any additional columns from the input keypoints beyond the first 5
                are preserved and appended after the converted columns.

Raises:
    ValueError: If the target_format is not one of the supported formats.

Note:
    - Input angles are assumed to be in the range [0, 2π) radians
    - If the input keypoints have additional columns beyond the first 5,
      these columns are preserved in the output

zUnknown target_format r   Nr   r   r   r      r   )	r   rb   r   r   r   r   degreesrh   r   )rX   target_formatrh   rp   r)   r   r   r   anglescaleformat_to_columnsresults               r    r   r     s/   Z ,,1-@YZjYklmm%adOYq!t_i1oyYZ\]Y]`ijkmnjn`ooA!Eu%Eq(?@%H

5! ffe}e}u$u$ay __.=>F qCC!5\5]2](^_``Mr!   )r   ry   rE   ry   )rX   ry   rh   r   rE   rx   )rX   ry   rh   r   r(   rD   rE   ry   )FT)rX   ry   r   8Literal['xy', 'yx', 'xya', 'xys', 'xyas', 'xysa', 'xyz']rh   r   rp   rD   r)   rD   rE   ry   )rX   ry   r   r   rh   r   rp   rD   r)   rD   rE   ry   )rL   
__future__r   r   collections.abcr   typingr   r   numpyr   $albumentations.core.type_definitionsr   utilsr	   r
   r   __all__r   r   r   r   r   r   r   r   r6   r!   r    <module>r      s!   #  $   X 3 3 E % T
V T
nw
 w
tE4P!!! ! 	!P !!MMKM M 	M
 M Mh !!IIKI I 	I
 I Ir!   