U
    h2                     @  sL  d dl mZ d dlZd dlmZ d dlmZmZmZmZm	Z	 d dl
Z
d dlZd dlmZmZmZ d dlmZmZ d dlmZ erd dlmZ d	d
dddgZedZedejdZededef dZddddd	Zddddd
ZdddddZdddddZ dddddZ!dd d d!dd"d#d$Z"G d%d& d&Z#dddd'd(Z$dS ))    )annotationsNwraps)TYPE_CHECKINGAnyCallableTypeVarcast)is_grayscale_imageis_multispectral_imageis_rgb_image)Concatenate	ParamSpec)angle_to_2pi_range)Pathread_bgr_imageread_rgb_imageread_grayscaleangle_2pi_rangenon_rgb_errorPT)boundF.z
str | Path
np.ndarray)pathreturnc                 C  s   t t| t jS N)cv2imreadstrZIMREAD_COLORr    r"   F/tmp/pip-unpacked-wheel-e8onvpoz/albumentations/augmentations/utils.pyr   #   s    c                 C  s   t | }t|tjS r   )r   r   ZcvtColorZCOLOR_BGR2RGB)r   imager"   r"   r#   r   '   s    c                 C  s   t t| t jS r   )r   r   r    ZIMREAD_GRAYSCALEr!   r"   r"   r#   r   ,   s    z0Callable[Concatenate[np.ndarray, P], np.ndarray])funcr   c                   s$   t  ddddd fdd}|S )Nr   zP.argszP.kwargs)	keypointsargskwargsr   c                   sN    | f||}t |dkrJ|jd dkrJt|d d df |d d df< |S )Nr         )lenshaper   )r&   r'   r(   resultr%   r"   r#   wrapped_function3   s     z)angle_2pi_range.<locals>.wrapped_functionr   )r%   r/   r"   r.   r#   r   0   s    None)r$   r   c                 C  s8   t | s4d}t| r|d7 }t| r,|d7 }t|dS )a  Check if the input image is RGB and raise a ValueError if it's not.

    This function is used to ensure that certain transformations are only applied to
    RGB images. It provides helpful error messages for grayscale and multi-spectral images.

    Args:
        image (np.ndarray): The input image to check. Expected to be a numpy array
                            representing an image.

    Raises:
        ValueError: If the input image is not an RGB image (i.e., does not have exactly 3 channels).
                    The error message includes specific instructions for grayscale images
                    and a note about incompatibility with multi-spectral images.

    Note:
        - RGB images are expected to have exactly 3 channels.
        - Grayscale images (1 channel) will trigger an error with conversion instructions.
        - Multi-spectral images (more than 3 channels) will trigger an error stating incompatibility.

    Example:
        >>> import numpy as np
        >>> rgb_image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
        >>> non_rgb_error(rgb_image)  # No error raised
        >>>
        >>> grayscale_image = np.random.randint(0, 256, (100, 100), dtype=np.uint8)
        >>> non_rgb_error(grayscale_image)  # Raises ValueError with conversion instructions
        >>>
        >>> multispectral_image = np.random.randint(0, 256, (100, 100, 5), dtype=np.uint8)
        >>> non_rgb_error(multispectral_image)  # Raises ValueError stating incompatibility
    z,This transformation expects 3-channel imagesz[
You can convert your grayscale image to RGB using cv2.cvtColor(image, cv2.COLOR_GRAY2RGB))z?
This transformation cannot be applied to multi-spectral imagesN)r   r
   r   
ValueError)r$   messager"   r"   r#   r   =   s    ztuple[float, float]floatz
str | None)valuelower_boundupper_boundnamer   c                   sZ   t  fdd| D s4td| d  d d| d | d ksVt|d	|  d
S )a  Checks if the given value is within the specified bounds

    Args:
        value: The value to check and convert. Can be a single float or a tuple of floats.
        lower_bound: The lower bound for the range check.
        upper_bound: The upper bound for the range check.
        name: The name of the parameter being checked. Used for error messages.

    Raises:
        ValueError: If the value is outside the bounds or if the tuple values are not ordered correctly.
    c                 3  s&   | ]} |  kokn  V  qd S r   r"   ).0xr5   r6   r"   r#   	<genexpr>r   s     zcheck_range.<locals>.<genexpr>zAll values in z must be within [z, z] for tuple inputs.r   r)   z2 tuple values must be ordered as (min, max). Got: N)allr1   )r4   r5   r6   r7   r"   r:   r#   check_rangef   s    r=   c                   @  sz   e Zd ZddddddZdddd	d
ZdddddZdddddZdddddZddddZddddZ	dS )PCANz
int | Noner0   )n_componentsr   c                 C  s4   |d k	r|dkrt d|| _d | _d | _d | _d S )Nr   z/Number of components must be greater than zero.)r1   r?   meancomponents_explained_variance_)selfr?   r"   r"   r#   __init__y   s    zPCA.__init__r   )r9   r   c                 C  sZ   | tj}|j\}}| jd kr,t||| _tj|d | jd\| _}}|| _	|
 | _d S )N)r@   ZmaxComponents)astypenpfloat64r,   r?   minr   ZPCACompute2r@   rA   flattenrB   )rC   r9   Z	n_samplesZ
n_featuresZeigenvectorsZeigenvaluesr"   r"   r#   fit   s    

zPCA.fitc                 C  s0   | j d krtd|tj}t|| j| j S NzgThis PCA instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.)rA   r1   rE   rF   rG   r   Z
PCAProjectr@   rC   r9   r"   r"   r#   	transform   s    
zPCA.transformc                 C  s   |  | | |S r   )rJ   rM   rL   r"   r"   r#   fit_transform   s    
zPCA.fit_transformc                 C  s$   | j d krtdt|| j| j S rK   )rA   r1   r   ZPCABackProjectr@   rL   r"   r"   r#   inverse_transform   s
    
zPCA.inverse_transform)r   c                 C  s(   | j d krtdt| j }| j | S )NzdThis PCA instance is not fitted yet. Call 'fit' with appropriate arguments before using this method.)rB   r1   rF   sum)rC   Ztotal_variancer"   r"   r#   explained_variance_ratio   s    
zPCA.explained_variance_ratioc                 C  s   t |  S r   )rF   ZcumsumrQ   )rC   r"   r"   r#   #cumulative_explained_variance_ratio   s    z'PCA.cumulative_explained_variance_ratio)N)
__name__
__module____qualname__rD   rJ   rM   rN   rO   rQ   rR   r"   r"   r"   r#   r>   x   s   		r>   c                   s,   t  ddddd fdd}tt|S )Nr   r   )arrayr'   r(   r   c                   s    t | dkr| S  | f||S )Nr   )r+   )rV   r'   r(   r.   r"   r#   wrapper   s    z#handle_empty_array.<locals>.wrapper)	functoolsr   r	   r   )r%   rW   r"   r.   r#   handle_empty_array   s    rY   )%
__future__r   rX   r   typingr   r   r   r   r	   r   ZnumpyrF   Zalbucore.utilsr
   r   r   Ztyping_extensionsr   r   Z#albumentations.core.keypoints_utilsr   pathlibr   __all__r   Zndarrayr   r   r   r   r   r   r   r=   r>   rY   r"   r"   r"   r#   <module>   s6   )7