
    Fg                      % S SK Jr  S SKrS SKJr  S SKJrJr  S SKJ	r	  S SK
r
S SKrS SKJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJ r J!r!J"r"J#r#J$r$  S SK%J&s  J's  J(r)  S SK*J+r+J,r,J-r-  S SK.J/r/J0r0  S S	K1J2r2J3r3J4r4  / S
Qr5\$\!          SS j5       5       r6\SS j5       r7\$\SS j5       5       r8SSS jjr9SSS jjr:        SS jr; S     SS jjr<\$\!   S         SS jj5       5       r=\$        SS j5       r>\      SS j5       r?\$\!        SS j5       5       r@\\!SS j5       5       rA\$\!        SS j5       5       rB\$        SS j5       rC      SS jrD\$            SS j5       rE\$\!                  SS j5       5       rF          SS jrG\$\\!            SS j5       5       5       rH\$\!\            SS j5       5       5       rI\$\            SS j5       5       rJ\$\!        SS  j5       5       rK\$\\!SS! j5       5       5       rLSS" jrMSS# jrNSS$ jrO\\          SS% j5       5       rPSS& jrQ\$\SS' j5       5       rR\SS( j5       rSSS) jrTSS* jrU\SS+ j5       rV        SS, jrW S     SS- jjrX\!\
R                  \
R                  4         SS. jj5       r[SS/ jr\\\\!SS0 j5       5       5       r]\!SS1 j5       r^\!SS2 j5       r_\\! S       SS3 jj5       5       r`SS4 jraSS5 jrb\$\!            SS6 j5       5       rc\\\!            SS7 j5       5       5       rd\!        SS8 j5       re\\\!SS9 j5       5       5       rf\\\!SS: j5       5       5       rg\$\              SS; j5       5       rh              SS< jri\!SS= j5       rj\!SS> j5       rk        SS? jrl\," S@5                SSA j5       rm0 SB/ SCQ_SD/ SEQ_SF/ SGQ_SH/ SIQ_SJ/ SKQ_SL/ SMQ_SN/ SOQ_SP/ SQQ_SR/ SSQ_ST/ SUQ_SV/ SWQ_SX/ SYQ_SZ/ S[Q_S\/ S]Q_S^/ S_Q_S`/ SaQ_Sb/ ScQ_/ SdQ/ SeQ/ SfQ/ SgQ/ ShQ/ SiQ/ SjQ/ SkQSl.E0 SF/ SmQ_SH/ SnQ_SJ/ SoQ_SL/ SpQ_SN/ SqQ_SP/ SrQ_SR/ SsQ_ST/ StQ_SV/ SuQ_SX/ SvQ_SZ/ SwQ_S\/ SxQ_S^/ SyQ_S`/ SzQ_Sb/ S{Q_S|/ S}Q_S~/ SQ_/ SQ/ SQ/ SQ/ SQ/ SQ/ SQS.ES.rnS\oS'   \        SS j5       rp\SS j5       rq  S         GS S jjrr\!\        GSS j5       5       rs        GSS jrt                GSS jru            GSS jrv            GSS jrw            GSS jrx        GSS jry        GSS jrz        GSS jr{        GSS jr|            GSS jr}\\!          GSS j5       5       r~        GS	S jr\GR                   " / SQ/ SQ/ SQ/\GR                  S9r\GR                   " / SQ/ SQ/ SQ/\GR                  S9rSr        GS
S jr\\          GSS j5       5       r\        GSS j5       rGSS jr\GSS j5       r\        GSS j5       r\          GSS j5       r\$          GSS j5       r            GSS jrGSS jr          GSS jr        GSS jr        GSS jrGSS jr        GSS jr              GSS jr\GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      \GR                   " / SQ/ SQ/5      S.rGSGSS jjrGSS jrGSS jr " S S5      r " S S5      rGSS jr " S S\5      r " S S\5      rGSSS jjr\\            GS S j5       5       rg(!      )annotationsN)Sequence)AnyLiteral)warn)MAX_VALUES_BY_DTYPEadd	add_arrayadd_constantadd_weightedclipclipped
float32_io
from_floatget_num_channelsis_grayscale_imageis_rgb_imagemaybe_process_in_chunksmultiplymultiply_addmultiply_by_arraymultiply_by_constantnormalize_per_imagepowerpreserve_channel_dimsz_lutto_floatuint8_io)PCAhandle_empty_arraynon_rgb_error)bboxes_from_masksmasks_from_bboxes)MONO_CHANNEL_DIMENSIONSNUM_MULTI_CHANNEL_DIMENSIONSNUM_RGB_CHANNELS)"add_fog
add_graveladd_rain
add_shadowadd_snow_bleachadd_snow_textureadd_sun_flare_overlayadd_sun_flare_physics_basedadjust_brightness_torchvisionadjust_contrast_torchvisionadjust_hue_torchvisionadjust_saturation_torchvisionchannel_shufflechromatic_aberrationclaheconvolvedilate	downscaleequalizeerode	fancy_pcagamma_transformimage_compressioninvert	iso_noiselinear_transformation_rgbmove_tone_curvenoop	posterize	shift_hsvsolarizesuperpixelsto_grayunsharp_maskc                2   US:X  a  US:X  a  US:X  a  U $ [        U 5      nU(       a?  US:w  d  US:w  a  SnSn[        SSS9  [        R                  " U [        R                  5      n [        R                  " U [        R
                  5      n [        R                  " U 5      u  pVnUS:w  ad  [        R                  " SS[        R                  S9n[        R                  " X-   S5      R                  [        R                  5      n[        XXSS	9nUS:w  a
  [        XbS
S	9nUS:w  a
  [        XsS
S	9n[        R                  " XVU45      n [        R                  " U [        R                   5      n U(       a%  [        R                  " U [        R"                  5      $ U $ )Nr   zqHueSaturationValue: hue_shift and sat_shift are not applicable to grayscale image. Set them to 0 or use RGB image   )
stacklevel   dtype   FinplaceT)r   r   cv2cvtColorCOLOR_GRAY2RGBCOLOR_RGB2HSVsplitnparangeint16modastypeuint8r   r   mergeCOLOR_HSV2RGBCOLOR_RGB2GRAY)	img	hue_shift	sat_shift	val_shiftis_grayhuesatvallut_hues	            x/Users/admin/workspace/ai/PDFMathTranslate/myenv/lib/python3.13/site-packages/albumentations/augmentations/functional.pyrD   rD   W   sF    A~)q.Y!^
 %G>Y!^II1
 ll3 2 23
,,sC--
.CIIcNMCcA~))As"((3&&,c299"((CS51A~348A~348
))SsO
$C
,,sC--
.C4;3<<S//0DD    c                   U R                   n[        U   nU[        R                  :X  a  [	        [        U5      S-   5       Vs/ s H  oDX-  :  a  X4-
  OUPM     nnU R                  n[        U [        R                  " XRS9SS9n [        U5      U R                  :w  a  [        R                  " U S5      $ U $ U R                  5       n X:  nX0U   -
  X'   U $ s  snf )a  Invert all pixel values above a threshold.

Args:
    img: The image to solarize. Can be uint8 or float32.
    threshold: Normalized threshold value in range [0, 1].
        For uint8 images: pixels above threshold * 255 are inverted
        For float32 images: pixels above threshold are inverted

Returns:
    Solarized image.

Note:
    The threshold is normalized to [0, 1] range for both uint8 and float32 images.
    For uint8 images, the threshold is internally scaled by 255.
   rM   FrP   )rN   r   rW   r\   rangeintshaper   arraylenndimexpand_dimscopy)r`   	thresholdrN   max_valilut
prev_shapeconds           ri   rE   rE      s    " IIE!%(GINsSZ|^_O_I`aI`AI$77Q>I`aYY
S"((34eD*-j/SXX*Er~~c2&N3N
((*CDd)#CIJ bs   Cc                $   [         R                  " U5      nUR                  (       a  [        U5      S:X  aR  [         R                  " SS[         R                  S9n[         R                  " SSU-
  -  S-
  5      ) nX4-  n[        XSS9$ [         R                  " U 5      n[        U5       Hb  u  pg[         R                  " SS[         R                  S9n[         R                  " SSU-
  -  S-
  5      ) nX4-  n[        U S	U4   US
S9US	U4'   Md     U$ )a  Reduce the number of bits for each color channel by keeping only the highest N bits.

This transform performs bit-depth reduction by masking out lower bits, effectively
reducing the number of possible values per channel. This creates a posterization
effect where similar colors are merged together.

Args:
    img: Input image. Can be single or multi-channel.
    bits: Number of high bits to keep. Must be in range [1, 7].
        Can be either:
        - A single value to apply the same bit reduction to all channels
        - A list of values to apply different bit reduction per channel.
          Length of list must match number of channels in image.

Returns:
    np.ndarray: Image with reduced bit depth. Has same shape and dtype as input.

Note:
    - The transform keeps the N highest bits and sets all other bits to 0
    - For example, if bits=3:
        - Original value: 11010110 (214)
        - Keep 3 bits:   11000000 (192)
    - The number of unique colors per channel will be 2^bits
    - Higher bits values = more colors = more subtle effect
    - Lower bits values = fewer colors = more dramatic posterization

Examples:
    >>> import numpy as np
    >>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
    >>> # Same posterization for all channels
    >>> result = posterize(image, bits=3)
    >>> # Different posterization per channel
    >>> result = posterize(image, bits=[3, 4, 5])  # RGB channels
rl   r   rL   rM   rJ      FrP   .T)rW   r\   rp   rr   rX   r   
empty_like	enumerate)r`   bits
bits_arrayry   mask
result_imgrx   channel_bitss           ri   rC   rC      s    J $Js:!3ii3bhh/q:~.233c..s#J$Z0ii3bhh/q</01455#CQKdC
36 1 rj   c                   [         R                  " U /S/US/S5      R                  5       nU Vs/ s H  o3(       d  M  UPM     nn[        U5      S::  a  U R	                  5       $ [
        R                  " US S 5      S-  nU(       d  U R	                  5       $ [
        R                  " S[
        R                  S9nUS-  n[        S5       H  n[        Xu-  S5      Xh'   XrU   -  nM     [        U [
        R                  " U5      S	S
9$ s  snf )Nr   rL   r   rL   rl   rm      rM   rJ   TrP   )rR   calcHistravelrr   ru   rW   sumemptyr\   rn   minr   rq   )	r`   r   	histogram_fhstepry   nrx   s	            ri   _equalize_pilr      s    cUQCuh?EEGI&i2iA&
1v{xxz66!CR&>S Dxxz
((3bhh
'C	A3ZQY$	q\  #rxx}d33 	's
   
DDc                F   Uc  [         R                  " U 5      $ [         R                  " U /S/US/S5      R                  5       nSnU H  nUS:  a    O	US-  nM     [	        US5      n[
        R                  " U5      nX#   U:X  a  [
        R                  " X5      $ SXRU   -
  -  nSn[
        R                  " S[
        R                  S9n[        US-   [        U5      5       H1  n	XrU	   -  n[        [        Xv-  5      [
        R                  5      X'   M3     [        XSS	9$ )
Nr   rL   r   rl   r   g     o@rM   TrP   )rR   equalizeHistr   r   r   rW   r   	full_likezerosr\   rn   rr   r   roundr   )
r`   r   r   rx   rg   totalscale_sumry   idxs
             ri   _equalize_cvr      s
   |$$cUQCuh?EEGI	A7	Q  	AsAFF9E|u||C##Uq\)*ED
((3bhh
'CQUC	N+#dl+RXX6 , #D))rj   c                    Ubx  [        U5      (       a5  [        U 5      (       a%  [        SU R                   SUR                   35      eU(       d+  [        U5      (       d  SUR                   3n[        U5      eg g g )NzWrong mask shape. Image shape: z. Mask shape: zAWhen by_channels=False only 1-channel mask supports. Mask shape: )r   r   
ValueErrorrp   )r`   r   by_channelsmsgs       ri   _check_preconditionsr     s    
 "4S"9"91#))N4::,W  #5d#;#;UVZV`V`UabCS/! $<{ rj   c                    U c  g U R                  [        R                  5      n [        U 5      (       d  Uc  U $ U SU4   $ )N.)r[   rW   r\   r   )r   rx   s     ri   _handle_maskr     s@     |;;rxx D$19Q<rj   c                   [        XU5        US:X  a  [        O[        n[        U 5      (       a  U" U [	        U5      5      $ U(       db  [
        R                  " U [
        R                  5      nU" US   [	        U5      5      US'   [
        R                  " U[
        R                  5      $ [        R                  " U 5      n[        [        5       H!  n[	        X5      nU" U SU4   U5      USU4'   M#     U$ )a  Apply histogram equalization to the input image.

This function enhances the contrast of the input image by equalizing its histogram.
It supports both grayscale and color images, and can operate on individual channels
or on the luminance channel of the image.

Args:
    img (np.ndarray): Input image. Can be grayscale (2D array) or RGB (3D array).
    mask (np.ndarray | None): Optional mask to apply the equalization selectively.
        If provided, must have the same shape as the input image. Default: None.
    mode (ImageMode): The backend to use for equalization. Can be either "cv" for
        OpenCV or "pil" for Pillow-style equalization. Default: "cv".
    by_channels (bool): If True, applies equalization to each channel independently.
        If False, converts the image to YCrCb color space and equalizes only the
        luminance channel. Only applicable to color images. Default: True.

Returns:
    np.ndarray: Equalized image. The output has the same dtype as the input.

Raises:
    ValueError: If the input image or mask have invalid shapes or types.

Note:
    - If the input image is not uint8, it will be temporarily converted to uint8
      for processing and then converted back to its original dtype.
    - For color images, when by_channels=False, the image is converted to YCrCb
      color space, equalized on the Y channel, and then converted back to RGB.
    - The function preserves the original number of channels in the image.

Example:
    >>> import numpy as np
    >>> import albumentations as A
    >>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
    >>> equalized = A.equalize(image, mode="cv", by_channels=True)
    >>> assert equalized.shape == image.shape
    >>> assert equalized.dtype == image.dtype
pil.r   .)r   r   r   r   r   rR   rS   COLOR_RGB2YCrCbCOLOR_YCrCb2RGBrW   r~   rn   r&   )r`   r   moder   functionr   rx   _masks           ri   r9   r9   +  s    Z K0 $}<H#\$/00\\#s':':;
%j&8,t:LM
6||J(;(;<<s#J#$T%%c#q&k59
36 % rj   c                n   [         R                  " SSS5      n        S
S jn[        U 5      n[         R                  " U5      (       aY  [         R                  " U5      (       a>  [	        [         R
                  " U" X1U5      5      [         R                  SS9n[        XSS9$ [        U[         R                  5      (       a  [        U[         R                  5      (       a  [	        [         R
                  " U" USS2[         R                  4   X5      R                  5      [         R                  SS9n[        R                  " [        U5       Vs/ s H.  n[        U SS2SS2U4   [         R                  " Xx   5      SS9PM0     sn5      $ [!        S[#        U5       S	[#        U5       35      es  snf )a  Rescales the relationship between bright and dark areas of the image by manipulating its tone curve.

Args:
    img: np.ndarray. Any number of channels
    low_y: per-channel or single y-position of a Bezier control point used
        to adjust the tone curve, must be in range [0, 1]
    high_y: per-channel or single y-position of a Bezier control point used
        to adjust image tone curve, must be in range [0, 1]

              ?rL   c                X    SU -
  nSUS-  -  U -  U-  SU-  U S-  -  U-  -   U S-  -   S-  $ )Nrl      rJ   r    )tlow_yhigh_yone_minus_ts       ri   evaluate_bez%move_tone_curve.<locals>.evaluate_bez~  sO    
 !eKN"Q&.[1a41G&1PPSTVWSWW[^^^rj   FrP   Nz?low_y and high_y must both be of type float or np.ndarray. Got z and )r   
np.ndarrayr   float | np.ndarrayr   r   returnr   )rW   linspacer   isscalarr   rintr\   r   
isinstancendarraynewaxisTrR   r]   rn   ascontiguousarray	TypeErrortype)	r`   r   r   r   r   num_channelsry   lutsrx   s	            ri   rA   rA   l  sw     	Cc"A__!_ #_ 
	_ $C(L	{{5bkk&11277<&9:BHHeTc..%$$FBJJ)G)GGGL1bjj=!15ACCDHH

 yyY^_kYlmYlTUVC1aL""6"6tw"?OYlm
 	
 
I$u+V[\`ag\h[ij  ns   5F2c                .    [         R                  " X5      $ N)rR   	transform)r`   transformation_matrixs     ri   r@   r@     s    
 ==44rj   c                j   U R                  5       n [        R                  " XS9n[        U 5      (       a  UR	                  U 5      $ [        R
                  " U [        R                  5      n UR	                  U SS2SS2S4   5      U SS2SS2S4'   [        R
                  " U [        R                  5      $ )a  Apply Contrast Limited Adaptive Histogram Equalization (CLAHE) to the input image.

This function enhances the contrast of the input image using CLAHE. For color images,
it converts the image to the LAB color space, applies CLAHE to the L channel, and then
converts the image back to RGB.

Args:
    img (np.ndarray): Input image. Can be grayscale (2D array) or RGB (3D array).
    clip_limit (float): Threshold for contrast limiting. Higher values give more contrast.
    tile_grid_size (tuple[int, int]): Size of grid for histogram equalization.
        Width and height of the grid.

Returns:
    np.ndarray: Image with CLAHE applied. The output has the same dtype as the input.

Note:
    - If the input image is float32, it's temporarily converted to uint8 for processing
      and then converted back to float32.
    - For color images, CLAHE is applied only to the luminance channel in the LAB color space.

Raises:
    ValueError: If the input image is not 2D or 3D.

Example:
    >>> import numpy as np
    >>> img = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
    >>> result = clahe(img, clip_limit=2.0, tile_grid_size=(8, 8))
    >>> assert result.shape == img.shape
    >>> assert result.dtype == img.dtype
)	clipLimittileGridSizeNr   )ru   rR   createCLAHEr   applyrS   COLOR_RGB2LABCOLOR_LAB2RGB)r`   
clip_limittile_grid_size	clahe_mats       ri   r5   r5     s    J ((*C*RI#s##
,,sC--
.C??3q!Qw<0C1aL<<S..//rj   c                D    [        [        R                  SUS9nU" U 5      $ )Nrm   )ddepthkernel)r   rR   filter2D)r`   r   conv_fns      ri   r6   r6     s      &cll2fMG3<rj   c                   US:X  a  [         R                  O[         R                  n[        U 5      nUS:X  a^  [         R                  " X [        U5      U45      u  pV[         R                  " U[         R                  5      nUS[        R                  4   $ U[        :X  aI  [         R                  " X [        U5      U45      u  pV[         R                  " U[         R                  5      $ US:X  ah  [        R                  " U SSS9n[         R                  " X([        U5      U45      u  pY[         R                  " U	[         R                  5      n
U
SSS24   $ U SS[        24   n[         R                  " X+[        U5      U45      u  pY[         R                  " U	[         R                  5      n
U[        :  a  / n[        [        U5       H  nU SU4   n[         R                  " X.[        U5      U45      u  p_[         R                  " U[         R                  5      n[        UR                  5      S:X  a  US[        R                  4   nUR!                  U5        M     [        R"                  " U
/UQ5      $ U
$ )	zApply compression to image.

Args:
    img: Input image
    quality: Compression quality (0-100)
    image_type: Type of compression ('.jpg' or '.webp')

Returns:
    Compressed image with same number of channels as input
z.jpgrl   .rJ   )r   r   r   r   rl   constant)r   N)rR   IMWRITE_JPEG_QUALITYIMWRITE_WEBP_QUALITYr   imencodero   imdecodeIMREAD_GRAYSCALErW   r   r&   IMREAD_UNCHANGEDpadrn   rr   rp   appenddstack)r`   quality
image_typequality_flagr   _encoded_imgdecodedpaddedencoded_bgrdecoded_bgrbgrextra_channelsrx   channelencodeds                   ri   r=   r=     s   " 0:V/C3++IaIaL#C(LqjL8I77ST,,{C,@,@AsBJJ''''jL8I77ST||K)=)=>> q5JGj3|;Lg:VWll;0D0DE37## c$$$$
%C\\*C4Ew3OPNA,,{C,@,@AK&&'6A#q&kGjC<Mw;WXJAll7C,@,@AG7==!Q&!#rzz/2!!'* 7 yy+7788rj   c                   [         [        R                     nXS-  -  nXS-  -  n[        R                  " U [        R
                  5      n[        R                  " U[        R                  S9nUSS2SS2S4   USS2SS2S4   U:  ==   U-  ss'   [        USS2SS2S4   [        R                  SS9USS2SS2S4'   [        R                  " U[        R                  S9n[        R                  " U[        R                  5      $ )a"  Adds a simple snow effect to the image by bleaching out pixels.

This function simulates a basic snow effect by increasing the brightness of pixels
that are above a certain threshold (snow_point). It operates in the HLS color space
to modify the lightness channel.

Args:
    img (np.ndarray): Input image. Can be either RGB uint8 or float32.
    snow_point (float): A float in the range [0, 1], scaled and adjusted to determine
        the threshold for pixel modification. Higher values result in less snow effect.
    brightness_coeff (float): Coefficient applied to increase the brightness of pixels
        below the snow_point threshold. Larger values lead to more pronounced snow effects.
        Should be greater than 1.0 for a visible effect.

Returns:
    np.ndarray: Image with simulated snow effect. The output has the same dtype as the input.

Note:
    - This function converts the image to the HLS color space to modify the lightness channel.
    - The snow effect is created by selectively increasing the brightness of pixels.
    - This method tends to create a 'bleached' look, which may not be as realistic as more
      advanced snow simulation techniques.
    - The function automatically handles both uint8 and float32 input images.

The snow effect is created through the following steps:
1. Convert the image from RGB to HLS color space.
2. Adjust the snow_point threshold.
3. Increase the lightness of pixels below the threshold.
4. Convert the image back to RGB.

Mathematical Formulation:
    Let L be the lightness channel in HLS space.
    For each pixel (i, j):
    If L[i, j] < snow_point:
        L[i, j] = L[i, j] * brightness_coeff

Examples:
    >>> import numpy as np
    >>> import albumentations as A
    >>> image = np.random.randint(0, 256, [100, 100, 3], dtype=np.uint8)
    >>> snowy_image = A.functional.add_snow_v1(image, snow_point=0.5, brightness_coeff=1.5)

References:
    - HLS Color Space: https://en.wikipedia.org/wiki/HSL_and_HSV
    - Original implementation: https://github.com/UjjwalSaxena/Automold--Road-Augmentation-Library
rJ   r   rM   Nrl   TrP   )
r   rW   r\   rR   rS   COLOR_RGB2HLSrq   float32r   COLOR_HLS2RGB)r`   
snow_pointbrightness_coeff	max_value	image_hlss        ri   r+   r+     s    h $BHH-Ia-Ja-JS#"3"34I"**5IaAgyAq)J67;KK7i1a0"((DIIaAg"((3I<<	3#4#455rj   c                    UR                  U SS SSS9n[        R                  " USSSS9nUR                  U SS 5      S	:  nX#4$ )
zGenerate snow texture and sparkle mask.

Args:
    img_shape (tuple[int, int]): Image shape.
    random_generator (np.random.Generator): Random generator to use.

Returns:
    tuple[np.ndarray, np.ndarray]: Tuple of (snow_texture, sparkle_mask) arrays.
NrJ         ?g333333?)sizelocr   r   rl   sigmaXsigmaYGz?)normalrR   GaussianBlurrandom)	img_shaperandom_generatorsnow_texturesparkle_masks       ri   generate_snow_texturesr  ^  s]     $**	"13c*RL##L&1ML $**9Ra=9D@L%%rj   c                l   [         [        R                     n[        R                  " U [        R
                  5      R                  [        R                  5      n[        R                  " USS2SS2S4   SX!-  -   -  SU5      USS2SS2S4'   [        R                  " USSSS9nU R                  S   n[        R                  " SSU5      SS2[        R                  4   nX8-  n[        R                  " U/S-  5      U-  U-  R                  [        R                  5      n	[        R                  " Xi5      n
[        R                  " U
S	5      n[        R                   " U
S
USU-  S5      n
[        R                  " U
R                  [        R                  5      [        R"                  5      n
XUU/X'   U
$ )a  Add a realistic snow effect to the input image.

This function simulates snowfall by applying multiple visual effects to the image,
including brightness adjustment, snow texture overlay, depth simulation, and color tinting.
The result is a more natural-looking snow effect compared to simple pixel bleaching methods.

Args:
    img (np.ndarray): Input image in RGB format.
    snow_point (float): Coefficient that controls the amount and intensity of snow.
        Should be in the range [0, 1], where 0 means no snow and 1 means maximum snow effect.
    brightness_coeff (float): Coefficient for brightness adjustment to simulate the
        reflective nature of snow. Should be in the range [0, 1], where higher values
        result in a brighter image.
    snow_texture (np.ndarray): Snow texture.
    sparkle_mask (np.ndarray): Sparkle mask.

Returns:
    np.ndarray: Image with added snow effect. The output has the same dtype as the input.

Note:
    - The function first converts the image to HSV color space for better control over
      brightness and color adjustments.
    - A snow texture is generated using Gaussian noise and then filtered for a more
      natural appearance.
    - A depth effect is simulated, with more snow at the top of the image and less at the bottom.
    - A slight blue tint is added to simulate the cool color of snow.
    - Random sparkle effects are added to simulate light reflecting off snow crystals.

The snow effect is created through the following steps:
1. Brightness adjustment in HSV space
2. Generation of a snow texture using Gaussian noise
3. Application of a depth effect to the snow texture
4. Blending of the snow texture with the original image
5. Addition of a cool blue tint
6. Addition of sparkle effects

Examples:
    >>> import numpy as np
    >>> import albumentations as A
    >>> image = np.random.randint(0, 256, [100, 100, 3], dtype=np.uint8)
    >>> snowy_image = A.functional.add_snow_v2(image, snow_coeff=0.5, brightness_coeff=0.2)

Note:
    This function works with both uint8 and float32 image types, automatically
    handling the conversion between them.

References:
    - Perlin Noise: https://en.wikipedia.org/wiki/Perlin_noise
    - HSV Color Space: https://en.wikipedia.org/wiki/HSL_and_HSV
NrJ   rl   r   r   r   g?r   )333333?      ?rl   333333?333333?)r   rW   r\   rR   rS   rU   r[   r   r   r  rp   r   r   r   r	   r   addWeightedr^   )r`   r   r   r	  r
  r   img_hsvrowsdepth_effect
snow_layerimg_with_snow	blue_tints               ri   r,   r,   u  sx   t $BHH-I ll3 1 1299"**EG ww1aA 0 ==>	GAq!G ##L&1ML 99Q<D;;q#t,Q

];L L ))\NQ./);jHPP


J
 GGG0M ]N;IOOz	M LL!5!5bhh!?ARARSM $-"CMrj   c           	     P   UR                   (       d  U R                  5       $ U R                  5       n [        R                  " U [        R                  S9nU[        R
                  " X//5      -   n	[        R                  " Xy4SS9n
[        R                  " UU
R                  [        R                  5      SUU[        R                  S9  US:  a  [        R                  " XU4US9  [        R                  " XU S9  US:w  a$  [        R                  " XU [        R                  S9  U $ )	z,Optimized version using OpenCV line drawing.rM   rl   axisF)lineTypedstr   )r  rN   )r   ru   rW   
zeros_liker\   rq   stackrR   	polylinesr[   int32LINE_4blurr	   r   CV_8U)r`   slantdrop_length
drop_width
drop_color
blur_valuebrightness_coefficient
rain_drops
rain_layer
end_pointsliness              ri   r)   r)     s     ??xxz
((*C s"((3J bhh(<'=>>J HHj-A6EMMRXX A~*5:FGGC%$ScKJrj   c           	         U SS u  pE[        S[        [        XE5      S-  U-  5      5      n[        SUS-  5      n[        U5       Vs/ s H  oR	                  Xv5      PM     sn$ s  snf )a[  Generate radiuses for fog particles.

Args:
    img_shape (tuple[int, int]): Image shape.
    num_particles (int): Number of fog particles.
    fog_intensity (float): Intensity of the fog effect, between 0 and 1.
    random_generator (np.random.Generator): Random generator to use.

Returns:
    list[int]: List of radiuses for each fog particle.
NrJ   皙?rl   )maxro   r   rn   integers)	r  num_particlesfog_intensityr  heightwidthmax_fog_radius
min_radiusr   s	            ri   get_fog_particle_radiusesr9    sk    " bqMMFCF 2S 8= HIJNQ!+,JKPQ^K_`K_a%%jAK_```s   A%c           	        U R                   SS u  pV[        U 5      n[        R                  " XVU4[        R                  S9n[
        [        R                     n	[        X45       H/  u  u  pnUS:X  a  U	OU	4U-  n[        R                  " UX4UUSS9  M1     [        R                  " USS5      n[        R                  " USS	S
9U	-  U-  U-  nU SU-
  -  X-  -   n[        U[        R                  S	S9$ )a  Add fog to the input image.

Args:
    img (np.ndarray): Input image.
    fog_intensity (float): Intensity of the fog effect, between 0 and 1.
    alpha_coef (float): Base alpha (transparency) value for fog particles.
    fog_particle_positions (list[tuple[int, int]]): List of (x, y) coordinates for fog particles.
    fog_particle_radiuses (list[int]): List of radiuses for each fog particle.

Returns:
    np.ndarray: Image with added fog effect.
NrJ   rM   rl   rm   )centerradiuscolor	thickness)   r?  r   Tr  keepdimsrP   )rp   r   rW   r   r\   r   ziprR   circler  meanr   )r`   r4  
alpha_coeffog_particle_positionsfog_particle_radiusesr5  r6  r   	fog_layerr   xyr<  r=  alpharesults                   ri   r'   r'   )  s    , IIbqMMF#C(L&6bhhGI#BHH-I4L)Q.	YL<4O

6	
 M   Ha8I GGIA5	AJNQ^^EAI!22F$//rj   c           	        U R                  5       nU R                  5       nSnSnU H>  u  n	u  ppXyU-  -  nX-  n[        R                  " XZU4XS5        [        XYUSU	-
  5      nM@     U V
s/ s H  n
[	        U
5      PM     nn
UR                  5       nUS-  nXx-  S-  n[
        R                  " S[        US5      US9n	[
        R                  " SX/S9n[        U5       HY  n[        R                  " X^[	        UU   5      US5        XU-
  S-
     XU-
  S-
     -  XU-
  S-
     -  n[        UUUSU-
  5      nM[     U$ s  sn
f )al	  Add a sun flare effect to an image using a simple overlay technique.

This function creates a basic sun flare effect by overlaying multiple semi-transparent
circles of varying sizes and intensities on the input image. The effect simulates
a simple lens flare caused by bright light sources.

Args:
    img (np.ndarray): The input image.
    flare_center (tuple[float, float]): (x, y) coordinates of the flare center
        in pixel coordinates.
    src_radius (int): The radius of the main sun circle in pixels.
    src_color (tuple[int, ...]): The color of the sun, represented as a tuple of RGB values.
    circles (list[Any]): A list of tuples, each representing a circle that contributes
        to the flare effect. Each tuple contains:
        - alpha (float): The transparency of the circle (0.0 to 1.0).
        - center (tuple[int, int]): (x, y) coordinates of the circle center.
        - radius (int): The radius of the circle.
        - color (tuple[int, int, int]): RGB color of the circle.

Returns:
    np.ndarray: The output image with the sun flare effect added.

Note:
    - This function uses a simple alpha blending technique to overlay flare elements.
    - The main sun is created as a gradient circle, fading from the center outwards.
    - Additional flare circles are added along an imaginary line from the sun's position.
    - This method is computationally efficient but may produce less realistic results
      compared to more advanced techniques.

The flare effect is created through the following steps:
1. Create an overlay image and output image as copies of the input.
2. Add smaller flare circles to the overlay.
3. Blend the overlay with the output image using alpha compositing.
4. Add the main sun circle with a radial gradient.

Examples:
    >>> import numpy as np
    >>> import albumentations as A
    >>> image = np.random.randint(0, 256, [100, 100, 3], dtype=np.uint8)
    >>> flare_center = (50, 50)
    >>> src_radius = 20
    >>> src_color = (255, 255, 200)
    >>> circles = [
    ...     (0.1, (60, 60), 5, (255, 200, 200)),
    ...     (0.2, (70, 70), 3, (200, 255, 200))
    ... ]
    >>> flared_image = A.functional.add_sun_flare_overlay(
    ...     image, flare_center, src_radius, src_color, circles
    ... )

References:
    - Alpha compositing: https://en.wikipedia.org/wiki/Alpha_compositing
    - Lens flare: https://en.wikipedia.org/wiki/Lens_flare
r   rm   rl   
      r   )num)	ru   rR   rC  r   ro   rW   r   r   rn   )r`   flare_center
src_radius	src_colorcirclesoverlayoutputweighted_brightnesstotal_radius_lengthrK  rI  rJ  rad3circle_colorpoint	num_times	max_alpharadrx   alps                       ri   r-   r-   Z  s[   @ hhjGXXZF-4)vtt|+#

7FD;gfa%i@	 .5 **\SV\E*kkmGb I
 $9A=IKKSC0i@E
++a
3C9

73s1v;	2>MA%&1}q/@)AAEVW-Z[J[D\\gsFAG< 
 M% +s   -D?c           
        U R                  5       nU R                  SS u  pg[        R                  " U [        R                  S9n[
        R                  " XX#S5        S H  n	[        US   [        R                  " [        R                  " U	5      5      [        Xv5      -  -   5      [        US   [        R                  " [        R                  " U	5      5      [        Xv5      -  -   5      4n
[
        R                  " XXS5        M     U H+  u  pp[
        R                  " X[        US-  5      US5        M-     [
        R                  " US	S
S
S9n[        R                  SU2SU24   u  nn[        R                  " UUS   -
  S-  XS   -
  S-  -   5      nS[        R                   " U[        Xv5      S-  -  SS5      -
  n[        R"                  " U/S-  5      nUU-  n[%        [
        R&                  " U5      5      n[
        R                  " US   S	SSS9US'   [
        R                  " US   S	SSS9US'   [
        R(                  " U5      nSSU-
  SU-
  -  S-  -
  $ )a0  Add a more realistic sun flare effect to the image.

This function creates a complex sun flare effect by simulating various optical phenomena
that occur in real camera lenses when capturing bright light sources. The result is a
more realistic and physically plausible lens flare effect.

Args:
    img (np.ndarray): Input image.
    flare_center (tuple[int, int]): (x, y) coordinates of the sun's center in pixels.
    src_radius (int): Radius of the main sun circle in pixels.
    src_color (tuple[int, int, int]): Color of the sun in RGB format.
    circles (list[Any]): List of tuples, each representing a flare circle with parameters:
        (alpha, center, size, color)
        - alpha (float): Transparency of the circle (0.0 to 1.0).
        - center (tuple[int, int]): (x, y) coordinates of the circle center.
        - size (float): Size factor for the circle radius.
        - color (tuple[int, int, int]): RGB color of the circle.

Returns:
    np.ndarray: Image with added sun flare effect.

Note:
    This function implements several techniques to create a more realistic flare:
    1. Separate flare layer: Allows for complex manipulations of the flare effect.
    2. Lens diffraction spikes: Simulates light diffraction in camera aperture.
    3. Radial gradient mask: Creates natural fading of the flare from the center.
    4. Gaussian blur: Softens the flare for a more natural glow effect.
    5. Chromatic aberration: Simulates color fringing often seen in real lens flares.
    6. Screen blending: Provides a more realistic blending of the flare with the image.

The flare effect is created through the following steps:
1. Create a separate flare layer.
2. Add the main sun circle and diffraction spikes to the flare layer.
3. Add additional flare circles based on the input parameters.
4. Apply Gaussian blur to soften the flare.
5. Create and apply a radial gradient mask for natural fading.
6. Simulate chromatic aberration by applying different blurs to color channels.
7. Blend the flare with the original image using screen blending mode.

Examples:
    >>> import numpy as np
    >>> import albumentations as A
    >>> image = np.random.randint(0, 256, [1000, 1000, 3], dtype=np.uint8)
    >>> flare_center = (500, 500)
    >>> src_radius = 50
    >>> src_color = (255, 255, 200)
    >>> circles = [
    ...     (0.1, (550, 550), 10, (255, 200, 200)),
    ...     (0.2, (600, 600), 5, (200, 255, 200))
    ... ]
    >>> flared_image = A.functional.add_sun_flare_physics_based(
    ...     image, flare_center, src_radius, src_color, circles
    ... )

References:
    - Lens flare: https://en.wikipedia.org/wiki/Lens_flare
    - Diffraction: https://en.wikipedia.org/wiki/Diffraction
    - Chromatic aberration: https://en.wikipedia.org/wiki/Chromatic_aberration
    - Screen blending: https://en.wikipedia.org/wiki/Blend_modes#Screen
NrJ   rM   rm   )r   -   Z      r   rl   gQ?r      r   ffffff?r   rO  r   )ru   rp   rW   r  r   rR   rC  ro   cosradiansr1  sinliner  ogridsqrtr   r   listrV   r]   )r`   rQ  rR  rS  rT  rV  r5  r6  flare_layerangle	end_pointr   r;  r   r=  rJ  rI  r   channelss                      ri   r.   r.     s-   J XXZFIIbqMMF --2::6K JJ{*D "Q"&&E):";c%>P"PPQQ"&&E):";c%>P"PPQ
	 	I!D " #*4

;D$JC #* "";r"MK 88GVGVeVO$DAq77AQ'A-!_1D0JJKDrwwts51C78!Q??D99dVaZ D 4K CIIk*+H""	HQK ""	HQK ))H%K 3<C+$56<==rj   c                   [        U 5      n[        [        R                     nU R	                  5       n[        X5       H  u  pg[        R                  " U R                  S   U R                  S   S4[        R                  S9n[        R                  " X/U45        [        R                  " XSS9nUSS2SS2S4   U:H  n	SU-
  n
[        XY   U
-  [        R                  SS9XY'   M     U$ )	a  Add shadows to the image by reducing the intensity of the pixel values in specified regions.

Args:
    img (np.ndarray): Input image. Multichannel images are supported.
    vertices_list (list[np.ndarray]): List of vertices for shadow polygons.
    intensities (np.ndarray): Array of shadow intensities. Range is [0, 1].

Returns:
    np.ndarray: Image with shadows added.

Reference:
    https://github.com/UjjwalSaxena/Automold--Road-Augmentation-Library
r   rl   rM   rJ   r  NTrP   )r   r   rW   r\   ru   rB  r   rp   rR   fillPolyrepeatr   )r`   vertices_listintensitiesr   r   img_shadowedverticesshadow_intensityr   shadowed_indicesdarknesss              ri   r*   r*   5  s    ( $C(L#BHH-I88:L '*-&E"xx1syy|Q7rxxHT:	|4 yy!4  1a=I5'')-*X5HH*
& 'F$ rj   c                    [        U 5        [        R                  " U [        R                  5      nU H  nUu  pEpgnXXE2Xg2S4'   M     [        R                  " U[        R                  5      $ )Nrl   )r!   rR   rS   r   r   )	r`   gravelsr   gravelmin_ymax_ymin_xmax_xrf   s	            ri   r(   r(   d  sd     #S#"3"34I*0'eC14%+u{A-.  <<	3#4#455rj   c                .    [         U R                     U -
  $ r   )r   rN   r`   s    ri   r>   r>   r  s     syy)C//rj   c                    U R                  5       n / n[        U5       H  u  p4UR                  X4/5        M     [        R                  " U /U /U5        U $ r   )ru   r   extendrR   mixChannels)r`   channels_shuffledfrom_torx   js        ri   r3   r3   x  sK    
((*CG+,v -OOSEC5'*Jrj   c                    U R                   [        R                  :X  aE  [        R                  " SSS5      U-  S-  n[	        XR                  [        R                  5      SS9$ [        R                  " X5      $ )Nr   g?gp?r   FrP   )rN   rW   r\   rX   r   r[   r   )r`   gammatables      ri   r<   r<     sW    
yyBHH1k95>#Ec<<15AA88Crj   c                   [         R                  " U [         R                  5      n[         R                  " U5      u  pVUR	                  US   U-  UR
                  SS S9nUR                  SX-  UR
                  SS S9nUS==   U-  ss'   [        US   Xr-  SUS   -
  -  5      US'   [         R                  " U[         R                  5      n	[        R                  " U	SSU	S	9$ )
aQ  Apply poisson noise to an image to simulate camera sensor noise.

Args:
    image (np.ndarray): Input image. Currently, only RGB images are supported.
    color_shift (float): The amount of color shift to apply.
    intensity (float): Multiplication factor for noise values. Values of ~0.5 produce a noticeable,
                       yet acceptable level of noise.
    random_generator (np.random.Generator): If specified, this will be random generator used
        for noise generation.

Returns:
    np.ndarray: The noised image.

Image types:
    uint8, float32

Number of channels:
    3
rl   NrJ   r   r   r   .rl   r   out)rR   rS   r   
meanStdDevpoissonrp   r  r
   r   rW   r   )
imagecolor_shift	intensityr  hlsr   stddevluminance_noisecolor_noise
noised_hlss
             ri   r?   r?     s    6 ,,uc//
0Cs#IA&..q	IYYr] / O #))	YYr] * K K;KF#sS['89CK
 c3#4#45J77:q!44rj   c                L    [         R                  " U [         R                  5      $ )a  Convert an RGB image to grayscale using the weighted average method.

This function uses OpenCV's cvtColor function with COLOR_RGB2GRAY conversion,
which applies the following formula:
Y = 0.299*R + 0.587*G + 0.114*B

Args:
    img (np.ndarray): Input RGB image as a numpy array.

Returns:
    np.ndarray: Grayscale image as a 2D numpy array.

Image types:
    uint8, float32

Number of channels:
    3
)rR   rS   r_   r  s    ri   to_gray_weighted_averager    s    & <<S//00rj   c                R    [         R                  " U [         R                  5      S   $ )a  Convert an RGB image to grayscale using the L channel from the LAB color space.

This function converts the RGB image to the LAB color space and extracts the L channel.
The LAB color space is designed to approximate human vision, where L represents lightness.

Key aspects of this method:
1. The L channel represents the lightness of each pixel, ranging from 0 (black) to 100 (white).
2. It's more perceptually uniform than RGB, meaning equal changes in L values correspond to
   roughly equal changes in perceived lightness.
3. The L channel is independent of the color information (A and B channels), making it
   suitable for grayscale conversion.

This method can be particularly useful when you want a grayscale image that closely
matches human perception of lightness, potentially preserving more perceived contrast
than simple RGB-based methods.

Args:
    img (np.ndarray): Input RGB image as a numpy array.

Returns:
    np.ndarray: Grayscale image as a 2D numpy array, representing the L (lightness) channel.
                Values are scaled to match the input image's data type range.

Image types:
    uint8, float32

Number of channels:
    3
r   )rR   rS   r   r  s    ri   to_gray_from_labr    s!    @ <<S../77rj   c                    U R                  [        R                  5      n[        R                  " USS9[        R                  " USS9-   S-  $ )zConvert an image to grayscale using the desaturation method.

Args:
    img (np.ndarray): Input image as a numpy array.

Returns:
    np.ndarray: Grayscale image as a 2D numpy array.

Image types:
    uint8, float32

Number of channels:
    any
rm   r  rJ   )r[   rW   r   r1  r   )r`   float_images     ri   to_gray_desaturationr    s<      **RZZ(KFF;R(266+B+GG1LLrj   c                ^    [         R                  " U SS9R                  U R                  5      $ )a7  Convert an image to grayscale using the average method.

This function computes the arithmetic mean across all channels for each pixel,
resulting in a grayscale representation of the image.

Key aspects of this method:
1. It treats all channels equally, regardless of their perceptual importance.
2. Works with any number of channels, making it versatile for various image types.
3. Simple and fast to compute, but may not accurately represent perceived brightness.
4. For RGB images, the formula is: Gray = (R + G + B) / 3

Note: This method may produce different results compared to weighted methods
(like RGB weighted average) which account for human perception of color brightness.
It may also produce unexpected results for images with alpha channels or
non-color data in additional channels.

Args:
    img (np.ndarray): Input image as a numpy array. Can be any number of channels.

Returns:
    np.ndarray: Grayscale image as a 2D numpy array. The output data type
                matches the input data type.

Image types:
    uint8, float32

Number of channels:
    any
rm   r  )rW   rD  r[   rN   r  s    ri   to_gray_averager    s$    < 773R ''		22rj   c                ,    [         R                  " U SS9$ )a  Convert an image to grayscale using the maximum channel value method.

This function takes the maximum value across all channels for each pixel,
resulting in a grayscale image that preserves the brightest parts of the original image.

Key aspects of this method:
1. Works with any number of channels, making it versatile for various image types.
2. For 3-channel (e.g., RGB) images, this method is equivalent to extracting the V (Value)
   channel from the HSV color space.
3. Preserves the brightest parts of the image but may lose some color contrast information.
4. Simple and fast to compute.

Note:
- This method tends to produce brighter grayscale images compared to other conversion methods,
  as it always selects the highest intensity value from the channels.
- For RGB images, it may not accurately represent perceived brightness as it doesn't
  account for human color perception.

Args:
    img (np.ndarray): Input image as a numpy array. Can be any number of channels.

Returns:
    np.ndarray: Grayscale image as a 2D numpy array. The output data type
                matches the input data type.

Image types:
    uint8, float32

Number of channels:
    any
rm   r  )rW   r1  r  s    ri   to_gray_maxr  )  s    @ 66#Brj   c                   U R                   nU R                  SU R                  S   5      n[        SS9nUR	                  U5      nUR                  U R                  SS 5      n[        US5      nU[        R                  :X  a	  [        XQS9$ U$ )aP  Convert an image to grayscale using Principal Component Analysis (PCA).

This function applies PCA to reduce a multi-channel image to a single channel,
effectively creating a grayscale representation that captures the maximum variance
in the color data.

Args:
    img (np.ndarray): Input image as a numpy array with shape (height, width, channels).

Returns:
    np.ndarray: Grayscale image as a 2D numpy array with shape (height, width).
                If input is uint8, output is uint8 in range [0, 255].
                If input is float32, output is float32 in range [0, 1].

Note:
    This method can potentially preserve more information from the original image
    compared to standard weighted average methods, as it accounts for the
    correlations between color channels.

Image types:
    uint8, float32

Number of channels:
    any
rm   rJ   rl   )n_componentsNmin_maxtarget_dtype)	rN   reshaperp   r   fit_transformr   rW   r\   r   )r`   rN   pixelspca
pca_result	grayscales         ri   to_gray_pcar  L  s    6 IIE[[SYYq\*F 1
C""6*J ""399Ra=1I#Iy9I8=8I:i4XyXrj   c                   US:X  a  [        U 5      nOhUS:X  a  [        U 5      nOVUS:X  a  [        U 5      nODUS:X  a  [        U 5      nO2US:X  a  [	        U 5      nO US:X  a  [        U 5      nO[        SU 35      e[        X15      $ )Nweighted_averagefrom_labdesaturationaverager1  r  zUnsupported method: )r  r  r  r  r  r  r   grayscale_to_multichannel)r`   num_output_channelsmethodrL  s       ri   rG   rG   v  s     ##)#.	:	!#&	>	!%c*	9	 %	5S!	5S!/x899$VAArj   c                r    US:X  a  U $ [         R                  " U 5      n[        R                  " U/U-  5      $ )aA  Convert a grayscale image to a multi-channel image.

This function takes a 2D grayscale image or a 3D image with a single channel
and converts it to a multi-channel image by repeating the grayscale data
across the specified number of channels.

Args:
    grayscale_image (np.ndarray): Input grayscale image. Can be 2D (height, width)
                                  or 3D (height, width, 1).
    num_output_channels (int, optional): Number of channels in the output image. Defaults to 3.

Returns:
    np.ndarray: Multi-channel image with shape (height, width, num_channels)
rl   )rW   squeezerR   r]   )grayscale_imager  squeezeds      ri   r  r    s9    & a zz/*H99hZ"5566rj   c                   U R                   S S u  pEU[        R                  :g  =(       d    U[        R                  :g  =(       a    U R                  [        R
                  :H  nU(       a  [        U 5      n [        R                  " U S UUUS9n[        R                  " XuU4US9nU(       a  [        U[        R
                  S9$ U$ )NrJ   )fxfyinterpolationr  r  )	rp   rR   INTER_NEARESTrN   rW   r\   r   resizer   )	r`   r   down_interpolationup_interpolationr5  r6  	need_cast
downscaledupscaleds	            ri   r8   r8     s     IIbqMMF 	C---X1CsGXGX1X 
))rxx
  sm(J zz*foEUVH:C:hRXX6QQrj   c                    U $ r   r   )	input_objparamss     ri   rB   rB     s    rj   c           	        U R                   n[        U 5      nU R                  SU5      n[        R                  " USS9nXE-
  nUS:X  a"  [        R
                  " U5      nUS   U-  U-  nO[        R                  " USS9n	[        R                  R                  U	5      u  pU
SSS2   R                  5       nX   n
USS2U4   n[        R                  " [        R                  " U[        R                  " X-  5      5      UR                  5      R                  nXH-   nUR                  U5      n[        R                  " USSUS9$ )	a3  Perform 'Fancy PCA' augmentation on an image with any number of channels.

Args:
    img (np.ndarray): Input image
    alpha_vector (np.ndarray): Vector of scale factors for each principal component.
                               Should have the same length as the number of channels in the image.

Returns:
    np.ndarray: Augmented image of the same shape, type, and range as the input.

Image types:
    uint8, float32

Number of channels:
    Any

Note:
    - This function generalizes the Fancy PCA augmentation to work with any number of channels.
    - It preserves the original range of the image ([0, 255] for uint8, [0, 1] for float32).
    - For single-channel images, the augmentation is applied as a simple scaling of pixel intensity variation.
    - For multi-channel images, PCA is performed on the entire image, treating each pixel
      as a point in N-dimensional space (where N is the number of channels).
    - The augmentation preserves the correlation between channels while adding controlled noise.
    - Computation time may increase significantly for images with a large number of channels.

Reference:
    Krizhevsky, A., Sutskever, I., & Hinton, G. E. (2012).
    ImageNet classification with deep convolutional neural networks.
    In Advances in neural information processing systems (pp. 1097-1105).
rm   r   r  rl   F)rowvarNr  )rp   r   r  rW   rD  stdcovlinalgeighargsortdotdiagr   r   )r`   alpha_vector
orig_shaper   img_reshapedimg_meanimg_centeredstd_devnoiseimg_coveig_valseig_vecs	sort_permimg_pcas                 ri   r;   r;     s0   D J#C(L ;;r<0L ww|!,H*Lq&&&Q')L8 &&e4  YY^^G4 TrTN**,	&AyL) FF8RWW\%<=>NN
 ! 	 "G ooj)G 777Aqg..rj   c                ^    US:X  a  [         R                  " U 5      $ US:X  a  U $ [        XSS9$ )Nr   rl   FrP   )rW   r  r   r`   factors     ri   r/   r/     s1    {}}S!!{
C//rj   c                |   US:X  a  U $ [        U 5      (       a  U R                  5       O2[        R                  " U [        R                  5      R                  5       nUS:X  aK  U R
                  [        R                  :w  a  [        US-   5      n[        R                  " XU R
                  S9$ [        XUSU-
  -  SS9$ )Nrl   r   r   rM   FrP   )r   rD  rR   rS   r_   rN   rW   r   ro   r   r   )r`   r  rD  s      ri   r0   r0   &  s    {
+C00388:cll3HZHZ6[6`6`6bD{99

"tcz?D||CSYY77TQZ%8%HHrj   c                
   US:X  d  [        U 5      (       a  U $ [        R                  " U [        R                  5      n[        R                  " U[        R                  5      nUS:X  a  U$ [        R
                  " XUSU-
  US9$ )Nrl   r   )r  )r   rR   rS   r_   rT   r  )r`   r  r  grays       ri   r2   r2   5  sl     {(--
<<S//0D<<c001DQ;4_COOCq6zY^$__rj   c                t   [         R                  " U [         R                  5      n [        R                  " SS[        R
                  S9n[        R                  " USU-  -   S5      R                  [        R                  5      n[        U S   USS9U S'   [         R                  " U [         R                  5      $ )Nr   rL   rM   rO   r   FrP   )rR   rS   rU   rW   rX   rY   rZ   r[   r\   r   r^   )r`   r  ry   s      ri   _adjust_hue_torchvision_uint8r  E  s    
,,sC--
.C
))As"((
+C
&&sV|#S
)
0
0
:CVc59CK<<S..//rj   c                ^   [        U 5      (       d  US:X  a  U $ U R                  [        R                  :X  a  [	        X5      $ [
        R                  " U [
        R                  5      n [        R                  " U S   US-  -   S5      U S'   [
        R                  " U [
        R                  5      $ )Nr   r   ih  )
r   rN   rW   r\   r  rR   rS   rU   rZ   r^   r  s     ri   r1   r1   O  s    #&A+

yyBHH,S99
,,sC--
.C&&Vv|3S9CK<<S..//rj   c                
   [         R                  " U5      (       d  U $ U R                  nUbd  [        U R                  S S 5      nXc:  aG  X6-  nU R                  S S u  p[	        X-  5      [	        X-  5      p[
        R                  " X
U4U5      n [        U USS9nSn[        U R                     n[         R                  " U 5      n U R                  [        :X  a  [         R                  " U SS9n [        U 5      n[        U5       H  nU SU4   n[         R                   " U5      nUS   S:X  a  USS  n[#        U5       H  u  nnUU[%        U5      -     (       d  M  UU:H  n[         R&                  " UU   5      nUR                  R(                  S	;   a6  [	        [         R*                  " U5      5      n[-        [        UU5      U5      nOUnUUU'   M     M     XPR                  :w  a  [
        R                  " XS S U5      $ U $ )
NrJ   rN  )
n_segmentscompactnessr   rm   r  .rl   )rx   ub)rW   anyrp   r1  ro   
fgeometricr  slicr   rN   ru   rs   r$   rt   r   rn   uniquer   rr   rD  kindr   r   )r  r  replace_samplesmax_sizer  r  r   r   r5  r6  
new_height	new_widthsegments	min_valuer   r   c
image_sp_cunique_labelsr   labelr   mean_intensityvalues                           ri   rF   rF   [  s    66/""J5;;r?#?OE!KKOMF$'$7U]9K	%%e)-DmTEH I#EKK0IGGENEzz,,u2.#E*L< 36]
		(+q )!"-M $M2JC sS%99::5(!#D)9!:##((O;
   89EE9 5yAE*E#(
4 # 3 !6 GQT_T_F_:UrNMBjejjrj   c                   [        [        R                  X4US9nU R                  [        :X  a$  [        U 5      S:X  a  [        R                  " U SS9n U" U 5      nX-
  n[        R                  " U5      S-  U:  nUR                  [        R                  5      nXU-  -   n	[        R                  " U	SSU	S9n	U" U5      n
[        [        X5      [        U SU
-
  5      SS	9$ )
N)ksizer  rl   rm   r  r   r   r  TrP   )r   rR   r  rs   r%   r   rW   r  absr[   r   r   r
   r   )r  r  sigmarK  rv   blur_fnr#  residualr   sharp	soft_masks              ri   rH   rH     s     &nG zz116Fu6MQR6R

5r*5>D|H 66(c!I-D;;rzz"DH$$EGGE1aU+EI"I& rj   c                0    [         R                  " XU 5      $ )a  Apply pixel dropout to an image.

Args:
    image: Input image
    drop_mask: Boolean mask of same shape as image indicating pixels to drop
    drop_values: Values to use for dropped pixels, same shape as image

Returns:
    Image with pixels dropped according to mask
)rW   where)r  	drop_maskdrop_valuess      ri   pixel_dropoutr    s      88IE22rj   c                    [        XSS9$ NFrP   r	   )r`   rains     ri   spatter_rainr    s     s%((rj   c                    [        X-  USS9$ r  r  )r`   non_mudmuds      ri   spatter_mudr    s     s}c511rj   c                   U R                   S S u  pg[        R                  " S[        R                  S9nXxS'   XhS'   US-  US'   US-  US'   [        R                  " XS	S	/[        R                  S9n	[        R                  " X4S	S	/[        R                  S9n
[        U S
   UU	UUU5      n[        U S   UU
UUU5      n[        R                  " XS   U/5      $ )NrJ   r   rM   r   )rl   rl   g       @)r   rJ   )rl   rJ   r   r   .rJ   r  )rp   rW   eyer   rq   _distort_channelr   )r`   primary_distortion_redsecondary_distortion_redprimary_distortion_bluesecondary_distortion_bluer  r5  r6  
camera_matdistortion_coeffs_reddistortion_coeffs_bluered_distortedblue_distorteds                ri   r4   r4     s     IIbqMMF ,Jtts{Jt|Jt HH	1a@jj  XX	 QBjj %FM &FN 99m[.ABBrj   c           	         [         R                  " UUS UXC4[         R                  S9u  pg[         R                  " U UUU[         R                  S9$ )N)cameraMatrix
distCoeffsRnewCameraMatrixr   m1type)r  
borderMode)rR   initUndistortRectifyMapCV_32FC1remapBORDER_REPLICATE)r   r   distortion_coeffsr5  r6  r  map_xmap_ys           ri   r  r    sV     ..$
"_||LE 99#'' rj   c                ,    [         R                  " XSS9$ Nrl   )
iterations)rR   r:   r`   r   s     ri   r:   r:   0  s    99SQ//rj   c                ,    [         R                  " XSS9$ r4  )rR   r7   r6  s     ri   r7   r7   5  s    ::ca00rj   c                b    US:X  a  [        X5      $ US:X  a  [        X5      $ [        SU 35      e)NdilationerosionzUnsupported operation: )r7   r:   r   )r`   r   	operations      ri   
morphologyr<  :  s=    
 Jc""IS!!
.yk:
;;rj   bboxesc                |    U R                  5       n [        X5      n[        XAU5      n[        U5      U S S 2S S24'   U $ )N   )ru   r#   r<  r"   )r=  r   r;  image_shapemaskss        ri   bboxes_morphologyrB  G  s@     [[]Ff2Eui0E%e,F1bqb5MMrj   i  )gk+ݓ?gӼ?g_LU?i  )a+e?gMSt$?gZd;O?i  )gD?gs?g_L?i  )g<Nё\?gJY?g:#J{/?i  )gJ4?gL7A`?g9m4?i|  )gݓ?gx&?gcZB?ip  )gj+?g-!lV?gF_?id  )g:pΈ?gŏ1w?g<,Ԛ?iX  )g<,Ԛ?g oŏ?gfj+?iL  )gu?goʡ?g?W[?i@  )gjMS?g1?gSt$?i4!  )gS?g)Ǻ?gvq-?i(#  )gsF?g:H?gl	g?i%  )gX9v?gW2?g^I+?i'  )gs?y?g6<R?i)  )gFx?Ӽ?gI.!?i*  )gd]K?n?gTN?)gW[?\ Ac?gW[?)g[<?rG  g鷯?)g4@?rG  g^)?)gZd;O?rF  gAf?)gz6>?rF  g%䃞?)gOjM?rF  gm?)glV}?rE  g
F%u?)g{Pk?rD  g:#J{/?),  .  0  2  4  6  8  :  )g,Ԛ?gAc]K?gQI?)goʡ?gZӼ?gY ?)gDio?gQI?g46<R?)gJ4?g<R!?gb48?)g,C?g.n?gGz?)rE  gBi?rE  )gU0*?g|гY?g|Pk?)g\C?go_?gF_?)gA`"?gGz?g9#J?)gBi?g&1?g<,Ԛ?)g:H?g9#?g镲q?)gkw#?gy)?g?W[?)g6;Nё?gV-?gz6>W[?)g]Fx?gX2ı.?g:H?)gjM?g|a2U0?rC  rH  )gHP?g-1?g"~j?rI  )g[B>٬?߾3?g?ܵ?)gʡE?rP  g`"?)gۊe?rP  gH}8?)gK7?rP  g58EGr?)gJ4?rP  g'?)g+e?rP  g?)gǘ?rP  g/n?)rJ  rK  rL  rM  rN  rO  )	blackbodyciedz!dict[str, dict[int, list[float]]]PLANCKIAN_COEFFSc                   U R                  5       n [        [        U   R                  5       5      n[	        [        U   R                  5       5      n[
        R                  " XU5      nSn[	        X-  U-  U5      n[        X-  S-   U-  U5      nXg:X  a!  [
        R                  " [        U   U   5      nOUX-
  Xv-
  -  n	SU	-
  n
U
[
        R                  " [        U   U   5      -  U	[
        R                  " [        U   U   5      -  -   n[        U S S 2S S 2S4   US   US   -  SS9U S S 2S S 2S4'   [        U S S 2S S 2S4   US   US   -  SS9U S S 2S S 2S4'   U $ )Ni  rl   r   TrP   rJ   )	ru   r   rS  keysr1  rW   r   rq   r   )r`   temperaturer   min_tempmax_tempr   t_leftt_rightcoeffsw_rightw_lefts              ri   planckian_jitterr^    s    ((*C#D)..01H#D)..01H ''+:K D		$F 		q	 D(G *4089'G,<=W"((#3D#9&#ABBWrxxT"7+P
 F
 
 (Aq!Gq	F1IC1aL
 (Aq!Gq	F1IC1aL Jrj   c                    [        XSS9$ r  r  )r`   r  s     ri   	add_noiser`    s    s5))rj   c           	        U R                   [        :X  a  U S[        R                  4   n U R                  SS u  pEXE-  nU R                  [        R                  5      [        R                  " U S-   5      -  n[        Xa-  S-  5      n[        R                  " US-  XX5      n	[        R                  " US-  XH5      n
[        R                  " U
 VVs/ s H  o  H  oU:  d  M
  X:  d  M  X4PM     M     snn5      nS[        R                  " XE4[        R                  S9-  n[        R                  " XE4[        R                  5      n[        U5       GHu  n[!        U5       H  u  nn[        US   5      [        US	   5      p[        S	X-
  5      [#        XKU-   S-   5      nn[        S	X-
  5      [#        X\U-   S-   5      nnUUU2UU24   nUX{U4   -
  n[        R$                  " US-  SS
9n[        R&                  UU2UU24   u  nnUU-
  S-  UU-
  S-  -   US-  -  nUUU-  -   nUUUU2UU24   :  nUU   UUU2UU24   U'   UUUU2UU24   U'   M     [        [)        U5      5       HW  nUU:H  n[        R*                  " U5      (       d  M%  [        R,                  " [        R.                  " U5      S	S
9SSS2   UU'   MY     GMx     U$ s  snnf )a  Simple Linear Iterative Clustering (SLIC) superpixel segmentation using OpenCV and NumPy.

Args:
    image (np.ndarray): Input image (2D or 3D numpy array).
    n_segments (int): Approximate number of superpixels to generate.
    compactness (float): Balance between color proximity and space proximity.
    max_iterations (int): Maximum number of iterations for k-means.

Returns:
    np.ndarray: Segmentation mask where each superpixel has a unique label.
.NrJ   ư>r   rm   rM   rl   r   r  )rs   r$   rW   r   rp   r[   r   r1  ro   rX   rq   onesr!  fullinfrn   r   r   r   rj  rr   r  rD  argwhere)r  r  r  max_iterationsr5  r6  
num_pixelsimage_normalized	grid_stepx_rangey_rangerJ  rI  centerslabels	distancesr   rx   r;  y_lowy_highx_lowx_highcrop
color_diffcolor_distanceyyxxspatial_distancedistancer   s                                  ri   r  r    s   " zz,,c2::o&KKOMFJ ||BJJ/"&&2FF Z,45Iii	Q9Gii	Q:Ghh NA'QY1:!'NG
 "''6/::F0I>""7+IAvvay>3vay>q  1=13v9}q?P3Q6E1=13u)ma>O3P6E $E&L%,$>?D 0A 66JVVJM;NXXeFlE&L89FB!#aAaA =)Q,O%6F(FFHifeFl(BCCD:B4.IeFlE&L01$778F5<v-.t4' ,, s7|$AQ;Dvvd||WWR[[%6Q?"E
 %/ #8 MG 	Os   K
#K
*K
c           	         [         R                  " U S5      nX1S-  -   U-  n[        UR                  U5      R	                  [
        R                  5      USS9n[        [
        R                  " USSUS9S5      $ )	a  Apply shot noise to the image by simulating photon counting in linear light space.

This function simulates photon shot noise, which occurs due to the quantum nature of light.
The process:
1. Converts image to linear light space (removes gamma correction)
2. Scales pixel values to represent expected photon counts
3. Samples actual photon counts from Poisson distribution
4. Converts back to display space (reapplies gamma)

The simulation is performed in linear light space because photon shot noise is a physical
process that occurs before gamma correction is applied by cameras/displays.

Args:
    img: Input image in range [0, 1]. Can be single or multi-channel.
    scale: Reciprocal of the number of photons (noise intensity).
        - Larger values = fewer photons = more noise
        - Smaller values = more photons = less noise
        For example:
        - scale = 0.1 simulates ~100 photons per unit intensity
        - scale = 10.0 simulates ~0.1 photons per unit intensity
    random_generator: NumPy random generator for Poisson sampling

Returns:
    Image with shot noise applied, same shape and range [0, 1] as input.
    The noise characteristics will follow Poisson statistics in linear space:
    - Variance equals mean in linear space
    - More noise in brighter regions (but less relative noise)
    - Less noise in darker regions (but more relative noise)

Note:
    - Uses gamma value of 2.2 for linear/display space conversion
    - Adds small constant (1e-6) to avoid issues with zero values
    - Clips final values to [0, 1] range
    - Operates on the image in-place for memory efficiency
    - Preserves float32 precision throughout calculations

References:
    - https://en.wikipedia.org/wiki/Shot_noise
    - https://en.wikipedia.org/wiki/Gamma_correction
g@rb  TrP   r   rl   r  g]tE?)	rR   powr   r  r[   rW   r   r   r   )r`   r   r  
img_linear
scaled_img	noisy_imgs         ri   
shot_noiser    su    ` c"J t|+u4J %  ,33BJJ?I Aqi8'BBrj   c                    U S:  a,  [         R                  " USU5      n[        XU-
  U-  5      nXC4$ [        X5      n[        X* U-  5      nXC4$ )a{  Calculate safe alpha and beta values to prevent overflow/underflow.

For any pixel value x, we want: 0 <= alpha * x + beta <= max_value

Args:
    alpha: Contrast factor (1 means no change)
    beta: Brightness offset
    max_value: Maximum allowed value (255 for uint8, 1 for float32)

Returns:
    tuple[float, float]: Safe (alpha, beta) values that prevent overflow/underflow
r   )rW   r   r   r1  )rK  betar   	safe_beta
safe_alphas        ri   #get_safe_brightness_contrast_paramsr  H  sd    " qy GGD!Y/	Y!6) CD
   	 (	
Y 67
  rj   c                .   Uc#  [         R                  " U[         R                  S9$  UR                  SS5      n[        R
                  " U5        US:X  a  [        U UUUU5      $ US:X  a$  US:X  a  [        U UUUU5      $ [        U UUUU5      $ US S u  p[        S[        X-  5      5      n
[        S[        X-  5      5      nX4USS  -   nUS:X  a  [        U UUUU5      nO[        U UUUU5      n[        R                  " XU	4[        R                  S	9$ )
NrM   r   i   r   r   sharedrJ   rl   r  )rW   r   r   r2  rR   
setRNGSeedgenerate_constant_noisegenerate_shared_noisegenerate_per_pixel_noiser1  ro   r  r  INTER_LINEAR)
noise_typespatial_moderp   r  r   approximationr  cv2_seedr5  r6  reduced_heightreduced_widthreduced_shaper  s                 ri   generate_noiser  i  sV    ~xxRZZ00?((E2HNN8z!&
 	
 8#(   (
 	
 "1IMFC 678N3u456M#3eABi?M x%
 )
 UUO3CSCSTTrj   c                V    [        U5      [        :  a  US   OSn[        U U4UUU5      $ )zGenerate one value per channel.rm   rl   )rr   r$   sample_noise)r  rp   r  r   r  r   s         ri   r  r    s9     !$E
-D D59!L	 rj   c                    [        XX#U5      $ )z-Generate separate noise map for each channel.)r  )r  rp   r  r   r  s        ri   r  r    s     
6>NOOrj   c                    U S:X  a  [        XU5      U-  $ U S:X  a  [        XU5      U-  $ U S:X  a  [        XU5      U-  $ U S:X  a  [        XU5      U-  $ [	        SU  35      e)z(Sample from specific noise distribution.uniformgaussianlaplacer  zUnknown noise type: )sample_uniformsample_gaussiansample_laplacesample_betar   )r  r   r  r   r  s        ri   r  r    s     Yd,<=	IIZt-=>JJYd,<=	IIV4)9:YFF
+J<8
99rj   c           
     h   [        U 5      S:X  a  US   nU S   n[        U5      S:X  a  X4-  nO)[        U5      U:  a  [        SU S[        U5       35      e[        R                  " USU  VVs/ s H  u  pVUR	                  XV5      PM     snn5      $ US   S   u  pVUR	                  XVU S9$ s  snnf )a  Sample from uniform distribution.

Args:
    size: Output shape. If length is 1, generates constant noise per channel.
    params: Must contain 'ranges' key with list of (min, max) tuples.
        If only one range is provided, it will be used for all channels.
    random_generator: NumPy random generator instance

Returns:
    Noise array of specified size. For single-channel constant mode,
    returns scalar instead of array with shape (1,).
rl   rangesr   z%Not enough ranges provided. Expected z, got Nr  )rr   r   rW   rq   r  )r   r  r  r  r   lowhighs          ri   r  r    s    " 4yA~!Awv;!*F[<'7~VCPVK=Y  xxBH,BWXBWYS%%c0BWX
 	

 x #IC##CD#99 Ys   /B.
c                   US   S   US   S   :X  a  US   S   OUR                   " US   6 nUS   S   US   S   :X  a  US   S   OUR                   " US   6 n[        U 5      [        :  a  U S   OSnU[        R                  " U4[        R
                  S9-  nU[        R                  " U4[        R
                  S9-  n[        R                  " U S9n[        R                  " XUS9  UR                  [        R
                  5      $ )	z"Sample from Gaussian distribution.
mean_ranger   rl   	std_rangerJ   )rp   rN   )rp   )r  rD  r  )
r  rr   r$   rW   rc  r   r   rR   randnr[   )	r   r  r  rD  r  r   mean_vectorstd_dev_vectorgaussian_sampled_arrs	            ri   r  r  	  s    ,"f\&:1&== 	|Q%%vl';< 	 +q!VK%8%;; 	{A%%vk':; 
 "$i*AA47qLbjjIIK277,

KKN88$/II&P&&rzz22rj   c                j    UR                   " US   6 nUR                   " US   6 nUR                  X4U S9$ )zSample from Laplace distribution.

The Laplace distribution is also known as the double exponential distribution.
It has heavier tails than the Gaussian distribution.
r  scale_range)r   r   r   )r  r  )r   r  r  r   r   s        ri   r  r  	  sD     
"
"F<$8
9C$$f]&;<E##t#DDrj   c                    UR                   " US   6 nUR                   " US   6 nUR                   " US   6 nUR                  X4U S9nSU-  S-
  U-  $ )zSample from Beta distribution.

The Beta distribution is bounded by [0, 1] and then scaled and shifted to [-scale, scale].
Alpha and beta parameters control the shape of the distribution.
alpha_range
beta_ranger  r  rJ   rl   )r  r  )r   r  r  rK  r  r   sampless          ri   r  r  -	  sm     $$f]&;<E##VL%9:D$$f]&;<E ##Ed#;GK!Ou$$rj   c                    USS u  pV[        U XV4UUU5      n[        U5      [        :  a  [        R                  " US   U5      $ U$ )a  Generate one noise map and broadcast to all channels.

Args:
    noise_type: Type of noise distribution to use
    shape: Shape of the input image (H, W) or (H, W, C)
    params: Parameters for the noise distribution
    max_value: Maximum value for the noise distribution
    random_generator: NumPy random generator instance

Returns:
    Noise array of shape (H, W) or (H, W, C) where the same noise
    pattern is shared across all channels
NrJ   .N)r  rr   r$   rW   broadcast_to)r  rp   r  r   r  r5  r6  	noise_maps           ri   r  r  @	  sW    * "1IMF	I 5z++y3U;;rj   c                D    [         R                  " U X"4UUS9nXX-
  -  -   $ )z"Sharpen image using Gaussian blur.)r  r  r  )rR   r  )r`   rK  kernel_sizer  blurreds        ri   sharpen_gaussianr  d	  s5     (	G #-(((rj   c           	         U R                   S:X  a
  US   nUS   n[        U R                     n[        R                  " X[        R                  " USU 5      5      $ )z>Apply salt and pepper noise to image using pre-computed masks.r   r  r   )rs   r   rN   rW   r  )r`   	salt_maskpepper_maskr   s       ri   apply_salt_and_pepperr  x	  sO     xx1}i(	!),#CII.I88I"((;3*GHHrj   )      ?r   r  )r   r   r   rM   )r   r  r   r   r   c                ~  ^ S	U4S jjn[        U 5      nS[        R                  " [        R                  " US-
  5      5      -  S-   n[	        [        R                  " US-
  5      S-
  5      n[        R
                  " [        U5       Vs/ s H  oqU-  PM	     sn5      nTR                  SSS5      R                  [        R
                  5      n	U H  n
U" X5      n	M     [        R                  " [        R                  " U	SU S   2SU S   24   SSS[        R                  [        R                  S9SS5      $ s  snf )
z3Generate Plasma Fractal with consistent brightness.c           	       > U R                   S   S-
  S-  S-   nU R                   S   S-
  S-  S-   n[        R                  " X#4[        R                  S9nT
R	                  U* XU45      R                  [        R                  5      nXS S S2S S S24   -   US S S2S S S24'   [        R                  " US[        [        R                  S9nUS:  nXFU-   U-  -  n[        R                  " US[        [        R                  S9nUS:  n	XHU-   U	-  -  n[        R                  " US SS[        R                  [        R                  S9$ )Nr   rl   rJ   rM   rm   )
borderType)rp   rW   r   r   r  r[   rR   r   DIAMOND_KERNELBORDER_CONSTANTSQUARE_KERNEL	normalizeNORM_MINMAXCV_32F)current_gridnoise_scalenext_height
next_widthexpanded_grid	all_noisediamond_interpolationdiamond_masksquare_interpolationsquare_maskr  s             ri   one_diamond_square_step8generate_plasma_pattern.<locals>.one_diamond_square_step	  sK   #))!,q0A59"((+a/14q8
 +!:"**M %,,k\;V`Habiijljtjtu	 #/3Q3!81D"Dcc3Q3h !$]B[^[n[n o,q0);|KK  #||M2}Y\YlYlm*Q.:kII }}]D!QszzZZrj   rJ   rl   rm   r  Nr   rM   )r  r   r  floatr   r   )r1  rW   ceillog2ro   r   rn   r  r[   r   rR   r  r  r  )target_shape	roughnessr  r  max_dimensionpower_of_two_sizetotal_stepsrx   noise_scalesplasma_gridr  s     `        ri   generate_plasma_patternr  	  s   [6 %MRWWRWW]Q->%?@@1Dbgg/!34q89K::U;5GH5G!|5GHIL #**2q&9@@LK $-kG $ 77k"3LO"35F|A5F"FGqRSUXUdUdlolvlvw		  Is   
D:c                   US:X  a  US:X  a  U $ U R                  5       n U R                  [        :  a:  [        R                  " US[        R
                  4   SSU R                  S   45      nUS:w  a  [        X1SS9n[        XSS9n US:w  a9  U R                  5       n[        X2SS9S-   n[        XSS9n USU-
  -  n[        XSS9$ U $ )	z7Apply plasma-based brightness and contrast adjustments.r   .rl   rm   FrP   Tr   )
ru   rs   r$   rW   tiler   rp   r   r	   rD  )r`   brightness_factorcontrast_factorplasma_patternbrightness_adjustmentrD  contrast_weightsmean_factors           ri    apply_plasma_brightness_contrastr  	  s     A/Q"6

((*C xx))RZZ!@1aSUBWX A (TY Z#d; !xxz#NUSVWWsd;c$4453T22Jrj   c                l    X!-  nU R                   [        :  a  US[        R                  4   nU SU-
  -  $ )zApply plasma-based shadow effect by darkening.

Args:
    img: Input image
    intensity: Shadow intensity in [0, 1]
    plasma_pattern: Generated plasma pattern of shape (H, W)

Returns:
    Image with applied shadow effect
.rl   )rs   r$   rW   r   )r`   r  r  scaled_patterns       ri   apply_plasma_shadowr  	  s?    " $/N xx))'RZZ8 !n$%%rj   c           	     
   US:X  aR  [         R                  " SSU[         R                  S9SSS24   [         R                  " U S4[         R                  S9-  $ US:X  aR  [         R                  " SSU[         R                  S9SSS24   [         R                  " U S4[         R                  S9-  $ US:X  aR  [         R                  " SSU [         R                  S9SS2S4   [         R                  " SU4[         R                  S9-  $ US:X  aR  [         R                  " SSU [         R                  S9SS2S4   [         R                  " SU4[         R                  S9-  $ US;   GaU  [         R                  " SSU[         R                  S9SSS24   n[         R                  " SSU [         R                  S9SS2S4   nUS	:X  a7  [        R
                  " X4-   SSS[        R                  [        R                  S9$ US
:X  a;  [        R
                  " SU-
  U-   SSS[        R                  [        R                  S9$ US:X  a>  [        R
                  " SU-
  SU-
  -   SSS[        R                  [        R                  S9$ [        R
                  " USU-
  -   SSS[        R                  [        R                  S9$ [         R                  " SSU [         R                  S9SS2S4   n[         R                  " SSU[         R                  S9SSS24   n[         R                  " U5      n[        R                  " U5      n[        R                  " U5      n[        R                  " X6US9  [        R                  " XGUS9  X4-   $ )u  Create a directional gradient in [0, 1] range.

Optimized implementation using broadcasting and fast paths for common angles:
- 0°, 180°: horizontal gradients using single linspace
- 90°, 270°: vertical gradients using single linspace
- 45°, 135°, 225°, 315°: diagonal gradients using equal combinations of horizontal and vertical
- Other angles: computed using trigonometric functions
r   rl   rM   NrO   rb  i  )ra  rc     i;  ra  rc  r  r  )rW   r   r   rc  rR   r  r  r  deg2radmathrf  rh  r   )r5  r6  rn  rI  rJ  	angle_radcos_asin_as           ri   create_directional_gradientr  
  s    z{{1abjj9$'BRWWfVW[`b`j`jEkkk|{{1abjj9$'BRWWfVW[`b`j`jEkkk {{{1arzz:1d7CbggqRWj`b`j`jFkkk|{{1arzz:1d7CbggqRWj`b`j`jFkkk ##KK1e2::6tQw?KK1fBJJ74@B;==aCOO3::VVC<==!a%1dAq#//QTQ[Q[\\C<==!a%AE!2D!QWZWaWabb}}Q!a%[$1cooSZZXX 	Aq&

3AtG<A
Aq%rzz247;A

5!IHHYEHHYELLq!LLq!5Lrj   c                T   U R                   SS u  p4[        U5      n[        X4U5      nUS:  a  [        R                  " SXfS9  [        R
                  " USU-  US9  [        R                  " USU-
  US9  U R                  [        :X  a  US[        R                  4   n[        X5      $ )az  Apply directional illumination effect to an image using a linear gradient.

The function creates a directional gradient and uses it to modulate image brightness.
The gradient direction is controlled by the angle parameter, and the strength of the
effect is controlled by the intensity parameter.

The illumination is applied by multiplying the image with a scale factor that varies
linearly across the image. The scale factor ranges from (1-|intensity|) to (1+|intensity|).

Args:
    img: Input image in range [0, 1]. Can be single or multi-channel.
    intensity: Strength and direction of the illumination effect, range [-1, 1].
        - Positive values brighten in gradient direction
        - Negative values darken in gradient direction
        - Magnitude determines strength of the effect
    angle: Direction of the gradient in degrees.
        - 0: left to right
        - 90: bottom to top
        - 180: right to left
        - 270: top to bottom

Returns:
    Image with applied illumination effect, same shape and range as input.

Implementation details:
    1. Creates a directional gradient in range [0, 1]
    2. For negative intensity, inverts the gradient (1 - gradient)
    3. For multi-channel images, repeats gradient across channels
    4. Computes scale factor in-place:
       scale = 1 - |intensity| + 2 * |intensity| * gradient
       This maps gradient [0, 1] to scale [(1-|i|), (1+|i|)]
    5. Multiplies image by scale factor

Note:
    Uses in-place operations where possible for memory efficiency.
    The @float32_io decorator ensures float32 precision.
    The @clipped decorator ensures output values stay in valid range.
NrJ   r   rl   r  .)rp   r  r  rR   subtractr   r	   rs   r%   rW   r   r   )r`   r  rn  r5  r6  abs_intensitygradients          ri   apply_linear_illuminationr  D
  s    P IIbqMMF	NM +6%@H1}Q/LL1},(;GGHa-'X6 xx//CO,S++rj   c                ~   US:X  a  U R                  5       $ U R                  SS u  p4[        R                  " X3-  XD-  -   5      n[        R
                  " X44S[        R                  S9nSSUS-
  4US-
  US-
  4US-
  S4/nSXgU   '   [        R                  " U[        R                  [        R                  [        R                  S9n[        R                  " X* U-  US	9  [        R                  " USUS	9  U R                  [        :X  a'  [        R                   " U/U R                  S   -  5      n[#        X5      $ )
z'Apply corner-based illumination effect.r   NrJ   r   rM   r   rl   )distanceTypemaskSizedstTyper  )ru   rp   r  rk  rW   rd  r\   rR   distanceTransformDIST_L2DIST_MASK_PRECISEr  r   r	   rs   r%   r]   r   )	r`   r  cornerr5  r6  diagonal_lengthr   cornerspatterns	            ri   apply_corner_illuminationr  
  s    A~xxzIIbqMMF ii%- ?@O 77F?Crxx8D 519~
EAI'>!QPGD ##[[&&

	G LL*6GDGGGQG$
xx//))WI		!45S**rj   c                   US:X  a  U R                  5       $ U R                  SS u  pEXRS   -  nXBS   -  nS[        XE5      U-  S-  -  n[        R                  SU2SU24   u  pU
R                  [        R                  5      n
U	R                  [        R                  5      n	X-  n
X-  n	[        R                  " XU
S9  [        R                  " XU	S9  X-   n
[        R                  " U
SU-  U
S9  [        R                  " XS9  [        R                  " XU
S9  [        R                  " U
SU
S9  U R                  [        :X  a'  [        R                  " U
/U R                  S   -  5      n
[        X
5      $ )z#Apply gaussian illumination effect.r   NrJ   rl   r  rm   )ru   rp   r1  rW   rj  r[   r   rR   r   expr	   rs   r%   r]   r   )r`   r  r;  r  r5  r6  center_xcenter_ysigma2rJ  rI  s              ri   apply_gaussian_illuminationr	  
  sG    A~xxzIIbqMMF ay Hq	!H#f$u,22F 88GVGVeVO$DA	A	AMAMA LL1LL1	A LLBKQ'GGA LL1%GGAqa
xx//IIqcCIIaL()S$$rj   c           	     >   U R                  5       n[        U 5      n[        U R                     nU R                  [
        :  a  [        R                  " U 5      n/ n[        U5       Hg  u  pUb  X:X  a  UR                  S5        M   Uc  SOX:g  n[        R                  " U
/S/US/SU/5      nUR                  UR                  5       5        Mi     [        U5       H  n	Ub  X:X  a  M  U R                  [
        :  a  WU	   nWU	   n
O8Uc  SOX:g  n[        R                  " U /S/US/SU/5      R                  5       nU n
[        X5      u  pX::  a  Mx  [        XXU5      nUb  X/U'   U R                  [
        :  a  [        X5      USU	4'   M  [        X5      nM     U$ )ao  Apply auto contrast to the image.

Args:
    img: Input image in uint8 or float32 format.
    cutoff: Percentage of pixels to cut off from the histogram edges.
           Range: 0-100. Default: 0 (no cutoff)
    ignore: Pixel value to ignore in auto contrast calculation.
           Useful for handling alpha channels or other special values.
    method: Method to use for contrast enhancement:
           - "cdf": Uses cumulative distribution function (original albumentations method)
           - "pil": Uses linear scaling like PIL.ImageOps.autocontrast

Returns:
    Contrast-enhanced image in the same dtype as input.
Nr   rL   .)ru   r   r   rN   rs   r$   rR   rV   r   r   r   r   rn   get_histogram_boundscreate_contrast_lutr   )r`   cutoffignorer  rL  r   r   rp  histsrx   r   r   histlohiry   s                   ri   auto_contrastr  
  s   , XXZF#C(L#CII.I xx))99S>"$#H-JA!akT"!>40AD<<	A3sea^LDLL& . < !+88--8DqkG!>4D<<sD3%!YHNNPDG%d38!$B6B K88--#G1F36NG)F/ !2 Mrj   c                   X:  a#  [         R                  " S[         R                  S9$ US:X  a  XUS-    nUR                  5       nUS   S:X  a#  [         R                  " S[         R                  S9$ XfS   -
  U-  US   US   -
  -  n[         R                  " S[         R                  S9n[         R
                  " [         R                  " U5      SU5      R                  [         R                  5      XqUS-   & X7US-   S& U$ X2U-
  -  n[         R                  " S[        S9n	[         R
                  " [         R                  " X-
  U-  5      SU5      R                  [         R                  5      nSUSU& X7US-   S& U$ )z,Create lookup table for contrast adjustment.rL   rM   cdfrl   rm   r   N)	rW   r   r\   cumsumrX   r   r   r[   r  )
r  min_intensitymax_intensityr   r  
hist_ranger  ry   r   indicess
             ri   r  r    s_    %xx288,,-!*;<
!r7a<99S11 V|y(CGc!f,<= hhs"((+13#91U1\1\]_]e]e1fMA-.#,MA 
 67Eii5)G ''"((G3u<=q)
L
S
STVT\T\
]CC(Jrj   c                   U(       dE  [         R                  " U 5      S   n[        U5      S:X  a  g[        US   5      [        US   5      4$ [	        U R                  5       5      nUS:X  a  gX1-  S-  n[        U 5      S:X  aN  [         R                  " X S   :H  5      (       a.  [        [        U 5      U-  S-  5      n[        U 5      U-
  S-
  nXV4$ SnSn[        [        U 5      5       H  nXpU   -  nXt:  d  M  US-   n  O   [        U[        U 5      S-
  5      nSn[        U 5      S-
  n[        [        U 5      S-
  SS5       H  nXpU   -  nXt:  d  M  Un  O   XV:  a  [        U 5      S-
  S	-  n	X4$ XV4$ )
z.Find the low and high bounds of the histogram.r   r   rm   g      Y@rL   d   rl   r   rJ   )	rW   nonzerorr   ro   r  r   allrn   r   )
r  r  non_zero_intensitiestotal_pixelspixels_to_cutr  r  r  rx   	mid_points
             ri   r  r  >  s   !zz$/2#$)'*+S1Eb1I-JJJ$Lq )E1M 4yCBFF47?33CI.45D	M1A5++ FM3t9q'"EM	 
 s4y1}5M FIMM3t9q="b)q'"M	 * $Y]q(	##''rj   c                    U(       d  [        U 5      S:X  a  UR                  SS/U USU-
  /S9$ UR                  SS/U SS USU-
  /S9n[        U 5      S:X  a  U$ [        R                  " US   U S   SS9$ )	a)  Generate a boolean mask for pixel dropout.

Args:
    shape: Shape of the input array
    per_channel: Whether to generate independent masks per channel
    dropout_prob: Probability of dropping a pixel
    random_generator: Random number generator

Returns:
    Boolean mask matching input shape
rJ   TFrl   )pNr  r  )rr   choicerW   rs  )rp   per_channeldropout_probr  mask_2ds        ri   get_drop_maskr)  m  s    " c%jAo&&5MQ-. ' 
 	
 %%	ubq	\)
* & G 5zQ 99WY'q::rj   c                    U[         R                  :X  a"  UR                  S[        [        U   5      U US9$ U[         R
                  :X  a   UR                  SSU S9R                  U5      $ [        SU 35      e)zGenerate random values for dropped pixels.

Args:
    channels: Number of channels in the image
    dtype: Data type of the image
    random_generator: Random number generator

Returns:
    Array of random values
r   )r   rN   rl   r  zUnsupported dtype: )	rW   r\   r2  ro   r   r   r  r[   r   )rp  rN   r  s      ri   generate_random_valuesr+    s     ((#E*+	 ) 
 	
 

''18'<CCEJJ
*5'2
33rj   c                   Uc"  [        U 5      n[        X0R                  U5      nOq[        U[        [
        45      (       a)  [        R                  " U R                  XR                  S9$ [        R                  " XR                  S9R                  S5      nU R                  S:X  a-  [        R                  " U R                  US   U R                  S9$ [        R                  " U R                  SS [        U5      4-   X@R                  S9$ )zPrepare values to fill dropped pixels.

Args:
    array: Input array to determine shape and dtype
    value: User-specified drop values or None for random
    random_generator: Random number generator

Returns:
    Array of values matching input shape
NrM   rm   rJ   r   )r   r+  rN   r   ro   r  rW   rd  rp   rq   r  rs   rr   )rq   r  r  rp  valuess        ri   prepare_drop_valuesr.    s     }#E*'++?OP	EC<	(	(wwu{{E==%{{3;;B? zzQwwu{{F1IU[[AA 775;;r?c&k^3V;;OOrj   c                8    SU ;   a  U S   $ SU ;   a  U S   S   $ S$ )z,Get mask array from input data if it exists.r   rA  r   Nr   )datas    ri   get_mask_arrayr1    s-    ~F|&$4=8D8rj   c                   [        U S-  [        R                  SS9n S[        R                  " U SS5      -
  n[        R
                  " U[        R                  S5      n[        R                  " USS[        R                  5      u  pC[        R                  " USS	S	[        R                  S
9n[        U[        R                  SS9n[        U5      n[        R                  " / SQ/ SQ/ SQ/[        R                  S9n[        X55      n[        R                  " USSS[        R                  S
9R                  [        R                  5      nU R                  [        R                  5      U-  n[        R                   " USS9nUS:  a	  US	U-  -  nO[        R"                  " U5      nUSS2SS2S4   U-  US-  -  nSU0$ )z$Generate parameters for rain effect.r   FrP   2      rO     r  rl   r  r  r  r  T)rm   r   )rm   rl   rl   )r   rl   rJ   rM   )rO  rO  g      ?r   r  r   Ng?drops)r   rW   r\   rR   Cannyr  r  rv   THRESH_TRUNCr  r/  r9   rq   r   r6   r[   r1  r  )	liquid_layerr=  r  distr   kermm_maxr8  s	            ri   get_rain_paramsr@    s    s*BHHeDL <S11D  s{{A6DmmD"b#*:*:;GA ''D bhh-D D>D ((	

 jjC DD '' fRZZ 	 	BJJ'$.A FF16"Eqy	QYMM! aDjME!Y_5E 	 rj   c                   U R                   u  pgX:  R                  [        R                  5      n[        R                  " U5      S:X  a^  Xg-  n	[        S[        SU	-  5      5      n
UR                  XSS9n[        R                  " U [        R                  S9nSUR                  U'   US:  a&  [        R                  " USUU[        R                  S	9n[        R
                  " U5      nUS:  a  X-  nOSUS'   X-  n[        R                  " XgS
4[        R                  S9n[        S
5       H  nXU   -  USU4'   M     [        R                  " U5      n[        S
5       HC  nX   S:  a.  [        R                   " X   USU4   -
  X   -  SS5      USU4'   M9  SU-
  USU4'   ME     UR                  [        R                  5      UR                  [        R                  5      S.$ )z5Generate mud effect parameters based on liquid layer.r   rl   r0  F)replacerM   r   r   r6  r   .)r  r  )rp   r[   rW   r   r   r1  ro   r%  r  flatrR   r  r/  r   rn   	ones_liker   )r;  r=  cutout_thresholdr  r  r  r5  r6  r   rh  
num_neededflat_indicesmask_maxr  rx   r  s                   ri   get_mud_paramsrI    s    !&&MF +33BJJ?D	vvd|q^
Cj 012
'..zu.U}}\<"%		, qy++
 vvd|H!| T
 D ((F1%RZZ
8C 1X1XoCF  ll3G1X8a< ggux#c1f+'=&I1aPGCFO!DjGCFO	  zz"**%>>"**- rj   g&c`?g8?gH?gm?g?g҈}?)gX ?g/'?gH.?)gQkw?g3ı.n?g$?)g?re  g(\?)gQ?r  )\(?)皙?g)\(?rL  )gQ?gQ?g\(\?)r  gQ?g{Gz?)g{Gz?g(\?g
ףp=
?)r  r  Q?)g(\?gffffff?r  )g(\?rM  rN  )g
ףp=
?g
ףp=
?gzG?)g=
ףp=?gQ?gRQ?)r  g{Gz?gzG?)ruifrokmacenkostandardhigh_contrasth_heavye_heavydarklightc                    [         U R                     nU R                  SS5      R                  [        R
                  5      n[        R                  " X2-  U5      n[        R                  " U5      * $ )Nrm   r   )r   rN   r  r[   rW   r   maximumlog)r`   epsr   pixel_matrixs       ri   rgb_to_optical_densityr\    sT    #CII.I;;r1%,,RZZ8L::l6<LFF<   rj   c                d    [         R                  " [         R                  " U S-  SSS95      nX-  $ )NrJ   rl   Tr@  )rW   rk  r   )vectorsnormss     ri   normalize_vectorsr`    s)    GGBFF7A:A=>E?rj   StainNormalizerc                6    U S:X  a
  [        5       $ [        5       $ )z%Get stain normalizer based on method.vahadane)VahadaneNormalizerMacenkoNormalizer)r  s    ri   get_normalizerrf    s    #)Z#7P=N=PPrj   c                  ,    \ rS rSrSrSS jrSS jrSrg)	ra  i  z!Base class for stain normalizers.c                    S U l         g r   stain_matrix_target)selfs    ri   __init__StainNormalizer.__init__  s
    #' rj   c                    [         e)z Extract stain matrix from image.)NotImplementedError)rk  r`   s     ri   fitStainNormalizer.fit  s    !!rj   ri  N)r   Noner`   r   r   rr  )__name__
__module____qualname____firstlineno____doc__rl  rp  __static_attributes__r   rj   ri   ra  ra    s    +("rj   c                  ,    \ rS rSrSSS jjrSS jrSrg)		SimpleNMFi  c                l    Xl         [        R                  " / SQ/ SQ/[        R                  S9U l        g )NrJ  rK  rM   )n_iterrW   rq   r   initial_colors)rk  r}  s     ri   rl  SimpleNMF.__init__  s,     hh.. **
rj   c                   U R                   R                  5       n[        U5      n[        R                  " XR
                  -  S5      nSn[        U R                  5       H  nXR
                  -  nXBUR
                  -  -  nXGX-   -  -  n[        R                  " US5      nUR
                  U-  nUR
                  U-  U-  nX'X-   -  -  n[        R                  " US5      n[        U5      nM     XB4$ )Nr   rb  )r~  ru   r`  rW   rX  r   rn   r}  )	rk  optical_densitystain_colorsstain_colors_normalizedstain_concentrationsrZ  r   	numeratordenominators	            ri   r  SimpleNMF.fit_transform  s    **//1 #4L"A!zz/<U<U*UWXY t{{#A'..8I.2OPK 1B$CC  $&::.BA#F  -..@I/114HHLXK):;;L ::lA6L,\:L! $$ $11rj   )r~  r}  N)r  )r}  ro   )r  r   r   tuple[np.ndarray, np.ndarray])rt  ru  rv  rw  rl  r  ry  r   rj   ri   r{  r{    s    	
2rj   r{  c                z   [        U 5      n [        R                  " [        R                  " U SS2S4   U SS2S4   5      [        R                  5      nU SS2S4   [        R
                  " U SS9S-   -  nU SS2S4   [        R
                  " U SS9S-   -  nX-  U-
  n[        R                  " U5      nSU-
  nXV4$ )zOrder stains using a combination of methods.

This combines both angular information and spectral characteristics
for more robust identification.
Nrl   r   rJ   r  rb  )r`  rW   rZ   arctan2pir   argmax)r  angles
blue_ratio	red_ratioscoreshematoxylin_idx	eosin_idxs          ri   order_stains_combinedr    s     %\2L VVBJJ|AqD1<13EFNF ad#rvvl'Cd'JKJQT"bff\&BT&IJI
  9,Fii'OO#I%%rj   c                      \ rS rSrSS jrSrg)rd  i  c                    [        U5      n[        SS9nUR                  U5      u  pE[        U5      u  pg[        R
                  " XV   XW   /5      U l        g )Nr  )r}  )r\  r{  r  r  rW   rq   rj  )rk  r`   r  nmfr   r  r  r  s           ri   rp  VahadaneNormalizer.fit  sY    05s#++O< &;<%H"#%88-'$
 rj   ri  Nrs  )rt  ru  rv  rw  rp  ry  r   rj   ri   rd  rd    s    
rj   rd  c                  B   ^  \ rS rSrSrSSU 4S jjjrSSS jjrSrU =r$ )	re  i  z5Macenko stain normalizer with optimized computations.c                .   > [         TU ]  5         Xl        g r   )superrl  angular_percentile)rk  r  	__class__s     ri   rl  MacenkoNormalizer.__init__  s    "4rj   c           	        [        U5      nSnX4:  R                  SS9nX5   n[        U5      S:  a  [        SU S35      e[        R
                  " U[        R                  S9n[        R                  " US[        R                  [        R                  -  [        R                  -  5      S   n[        R                  " U5      SS u  p[        R                  " UR                  5       5      S	S n
[        R
                  " U	SS2U
4   [        R                  S9nXk-  n[        R                  " USS2S4   USS2S4   5      n[        R                   " US
U-
  5      n[        R                   " X5      n[        R"                  " U5      [        R$                  " U5      nn[        R"                  " U5      [        R$                  " U5      nn[        R&                  " UU/UU//[        R                  S9n[        R(                  " UUR*                  SSS5      n[        R,                  " U5      nU[        R.                  " [        R0                  " US-  SSS95      -  nUS   US   :  a  UU l        gUSSS2   U l        g)z:Extract H&E stain matrix using optimized Macenko's method.g?rl   r  z"No tissue pixels found (threshold=)rM   Nr   r7  r  rJ   Tr@  r   )rl   r   rm   )r\  r  rr   r   rW   r   r   rR   calcCovarMatrixCOVAR_NORMAL
COVAR_ROWSCOVAR_SCALEeigenr  r   r  
percentilerf  rh  rq   gemmr   r  rk  r   rj  )rk  r`   r  r  od_thresholdthreshold_masktissue_densityod_covarianceeigenvalueseigenvectorsr   principal_eigenvectorsplane_coordinatespolar_angleshematoxylin_angleeosin_anglehem_coshem_sineos_coseos_sinangle_to_vectorstain_vectorss                         ri   rp  MacenkoNormalizer.fit  sL    15 )8==1=E(8~"A,qQRR --nBJJO++s~~-?
 	 %(IIm$<QR$@!jj**,-bc2!#!5!5l1c66JRTR\R\!] +C zzad#ad#
 MM,>P8PQmmLE 66"34bff=N6O66+.{0C((w'7!34**
 "$$
 }- &}a7GaZ^0_(`` 5B$4G-X\J]4]= cpqusuqucv rj   )r  rj  )c   )r  r  )r`   r   r  r  r   rr  )	rt  ru  rv  rw  rx  rl  rp  ry  __classcell__)r  s   @ri   re  re    s    ?5 5@w @wrj   re  c                `    U S   S-  U S   S-  -   U S   S-  -   nX!:  nUR                  S5      $ )a>  Get binary mask of tissue regions based on luminosity.

Args:
    img: RGB image in float32 format, range [0, 1]
    threshold: Luminosity threshold. Pixels with luminosity below this value
              are considered tissue. Range: 0 to 1. Default: 0.85

Returns:
    Binary mask where True indicates tissue regions
r   gA`"?r  gbX9?r  gv/?rm   )r  )r`   rv   
luminosityr   s       ri   get_tissue_maskr  K  sG     Vu$s6{U'::S[5=PPJ !D<<rj   c                   [        U 5      n[        R                  " U[        R                  S9nSnXR                  -  U[        R
                  " S5      -  -   nXR                  -  n [        R                  R                  Xx5      R                  n	U(       d'  [        U 5      R                  S5      n
X   U-  U-   X'   OX-  U-   n	X-  n[        R                  " U* 5      nUR                  U R                  5      $ ! [        R                  R                   a9    [        R                  R                  UR                  UUS9S   R                  n	 Nf = f)NrM   rb  rJ   )rcondr   rm   )r\  rW   r   r   r   r  r  solveLinAlgErrorlstsqr  r  r  rp   )r`   stain_matrixscale_factorsshift_valuesaugment_backgroundr  regularizationstain_correlationdensity_projectionr  tissue_maskoptical_density_result
rgb_results                ri   apply_he_stain_augmentationr  _  sB    -S1O ''BJJGL N$~~5PQ8RR%(9(99	!yy/@UWW %c*2226,@,MP],]`l,l)  4ClR 2@//0Jcii((+ 99   !yyNN   /  
 	  Q	 	s   ()C< <AEE)
r`   r   ra   r  rb   r  rc   r  r   r   )r`   r   rv   r  r   r   )r`   r   r   zALiteral[1, 2, 3, 4, 5, 6, 7] | list[Literal[1, 2, 3, 4, 5, 6, 7]]r   r   r   )r`   r   r   np.ndarray | Noner   r   )r`   r   r   r  r   boolr   rr  )r   r  rx   
int | Noner   r  )NcvT)
r`   r   r   r  r   zLiteral['cv', 'pil']r   r  r   r   )r`   r   r   r   r   r   r   r   )r`   r   r   r   r   r   )r`   r   r   r  r   tuple[int, int]r   r   )r`   r   r   r   r   r   )r`   r   r   ro   r   zLiteral['.jpg', '.webp']r   r   )r`   r   r   r  r   r  r   r   )r  r  r  np.random.Generatorr   r  )r`   r   r   r  r   r  r	  r   r
  r   r   r   )r`   r   r%  r  r&  ro   r'  ro   r(  tuple[int, int, int]r)  ro   r*  r  r+  r   r   r   )
r  r  r3  ro   r4  r  r  r  r   	list[int])r`   r   r4  r  rE  r  rF  zlist[tuple[int, int]]rG  r  r   r   )r`   r   rQ  tuple[float, float]rR  ro   rS  tuple[int, ...]rT  	list[Any]r   r   )r`   r   rQ  r  rR  ro   rS  r  rT  r  r   r   )r`   r   rt  zlist[np.ndarray]ru  r   r   r   )r`   r   r|  r  r   r   )r`   r   r   r   )r`   r   r  r   r   r   )r`   r   r  r  r   r   )
r  r   r  r  r  r  r  r  r   r   )r`   r   r  ro   r  zPLiteral['weighted_average', 'from_lab', 'desaturation', 'average', 'max', 'pca']r   r   )r   )r  r   r  ro   r   r   )
r`   r   r   r  r  ro   r  ro   r   r   )r  r   r  r   r   r   )r`   r   r  r   r   r   )r`   r   r  r   r   rW   )r`   r   r  r  r   r   )r   )r`   r   r  r  r  r  r   r   )r  r   r  ro   r  zSequence[bool]r  r  r  ro   r   r   )r  r   r  ro   r  r  rK  r  rv   ro   r   r   )r  r   r  r   r  r   r   r   )r`   r   r  r   r   r   )r`   r   r  r   r  r   r   r   )r`   r   r  r  r  r  r  r  r  r  r  ro   r   r   )r   r   r   r   r0  r   r5  ro   r6  ro   r  ro   r   r   )r`   r   r   r   r;  Literal['dilation', 'erosion']r   r   )
r=  r   r   r   r;  r  r@  r  r   r   )r`   r   rV  ro   r   zLiteral['blackbody', 'cied']r   r   )r`   r   r  r   r   r   )g      $@rN  )
r  r   r  ro   r  r  rg  ro   r   r   )r`   r   r   r  r  r  r   r   )rK  r  r  r  r   r  r   r  )r  1Literal['uniform', 'gaussian', 'laplace', 'beta']r  z*Literal['constant', 'per_pixel', 'shared']rp   r  r  zdict[str, Any] | Noner   r  r  r  r  r  r   r   )r  r  rp   r  r  dict[str, Any]r   r  r  r  r   r   )r  r  r   r  r  r  r   r  r  r  r   r   )r   r  r  r  r  r  r   znp.ndarray | float)r   r  r  r  r  r  r   r   )
r`   r   rK  r  r  ro   r  r  r   r   )r`   r   r  r   r  r   r   r   )r  r  r  r  r  r  r   r   )
r`   r   r  r  r  r  r  r   r   r   )r`   r   r  r  r  r   r   r   )r5  ro   r6  ro   rn  r  r   r   )r`   r   r  r  rn  r  r   r   )r`   r   r  r  r  zLiteral[0, 1, 2, 3]r   r   )
r`   r   r  r  r;  r  r  r  r   r   )
r`   r   r  r  r  r  r  Literal['cdf', 'pil']r   r   )r  r   r  ro   r  ro   r   ro   r  r  r   r   )r  r   r  r  r   r  )
rp   r  r&  r  r'  r  r  r  r   r   )rp  ro   rN   znp.dtyper  r  r   r   )rq   r   r  z+float | Sequence[float] | np.ndarray | Noner  r  r   r   )r0  r  r   r  )r;  r   r=  r   r  r  r   r  )r;  r   r=  r   rE  r  r  r  r  r  r  r  r   r  )rb  )r`   r   rZ  r  r   r   )r^  r   r   r   )r  zLiteral['vahadane', 'macenko']r   ra  )r  r   r   r  )r  )r`   r   r  r   r  r   r  r   r  r  r   r   )
__future__r   r  collections.abcr   typingr   r   warningsr   rR   numpyrW   albucorer   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   1albumentations.augmentations.geometric.functionalaugmentations	geometric
functionalr  "albumentations.augmentations.utilsr   r    r!   albumentations.core.bbox_utilsr"   r#   $albumentations.core.type_definitionsr$   r%   r&   __all__rD   rE   rC   r   r   r   r   r9   rA   r@   r5   r6   r=   r+   r  r,   r)   r9  r'   r-   r.   r*   r(   r>   r3   r<   r?   r  r  r  r  r  r  rG   r  
INTER_AREAr  r8   rB   r;   r/   r0   r2   r  r1   rF   rH   r  r  r  r4   r  r:   r7   r<  rB  rS  __annotations__r^  r`  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rq   r   r  r  INITIAL_GRID_SIZEr  r  r  r  r  r  r	  r  r  r  r)  r+  r.  r1  r@  rI  STAIN_MATRICESr\  r`  rf  ra  r{  r  rd  re  r  r  r   rj   ri   <module>r     s0   "  $   
       4 G F 
 P #L 
'E	'E'E 'E 	'E
 'E  
'ET 	 	D 
4 	 
4n4(*8"	"
" " 
	"" 



 
 
 #!%	<	<
< < 	<
 <  
<~ 
*	** * 	* 
*Z 	5	5%5 5 	5 
-0	-0-0 $-0 	-0  
-0` 	  	
 
9	99 )9 	9  
9x 
A6	A6A6 A6 	A6 
A6H&&)& #&. 
i	ii i 	i
 i i 
iX 
*	** * 	*
 %* * "* * *  
*Zaaa a *	a
 a0 
+0	+0+0 +0 2	+0
 %+0 +0  	 
+0\ 
[	[%[ [ 	[
 [ [   
[| 
u>	u>!u> u> $	u>
 u> u> 	 
u>p 
*	*#* * 	*  
*Z 
6  	 
60  -5-5-5 -5 *	-5
 -5 	 -5`1, 
8 	 
8B 	M 	M&3B  F 	&Y 	&YRB	BBB B@  !777 78  "nn,,	R	RR R 	R
 R R6 F/  	 F/R 0 0 I I 	 `	`` ` 	`  	`0	0 
=k=k=k $=k 	=k
 =k =k  
=k@ !!! ! 	!
 ! !  	 !H 333 3 	3 3$ )  	 ) 2  	 2 
-C	-C!-C $-C #	-C
  %-C -C -C 	 
-C` " 	
   2 0 0 1 1
<	
<
< .
< 	
< H


 .
 !	

 
 
'' 	' 	'	
 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	(  	(!" 	(#$ )(((((((36'' 	' 	'	
 	' 	' 	' 	' 	' 	' 	' 	' 	( 	( 	(  	(!" 	(#$ )(((((/957 3 5p 	-	-- '- 	- 	-` 	* 	* 	BBB B 	B
 BJ ;C	;C;C *;C 	;C  ;C|!!
! ! 	!BCUACU<CU CU "	CU
 CU CU *CU CULA  	
 * $PAPP P 	P
 *P P:A:
: : 	:
 *: :(":
":": *": 	":J3
33 *3 	32E
EE *E 	E%
%% *% 	%&!A!! ! 	!
 *! !H 	)	)) ) 	)
 )  	)$I	II I 	I  
 ** 
 **  2!22 *2 	2j 	 	     	 
    	 F 	&	&& & 	& 	&4.b 7, 7,t 	%+	%+%+  %+ 	%+ 	%+P 	)%	)%)%  )% 	)%
 )% 	)%X 
>	>> > "	>
 > 
>B$
$$ $ 	$
 "$ $N,(^$;$;$; $; *	$;
 $;N444 *4 	48PP6P *P 	P>9??? ? 	?D<<< < 	<
 < *< <B xx**	
 xx$$	
 	
 XX	
 xx	
 xx	
 HH	
 XX	
W1h! !
Q
" ")2 )2X&6
 
$Gw GwT( 	*)	*)*) *) 	*)
 *) *)  	*)rj   