a
    dn                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlm	Z	 d dl
mZ dd Zdd Zd	d
 Zdd ZdNddZdOddZdPddZdQddZdRddZdSddZdddej ejfdddfddZejddd  dTd!d"ZdUd%d&ZdVd'd(ZdWd)d*ZdXd+d,ZdYd.d/ZdZd1d2Zd[d3d4Z d\d5d6Z!d]d8d9Z"d^d:d;Z#d_d<d=Z$d`d>d?Z%dad@dAZ&dbdBdCZ'dcdDdEZ(dddFdGZ)dedIdJZ*dfdLdMZ+dS )g    N)special)multivariate_normal)rgb_to_grayscalec                 C   sd   t | d dgd|d gg}t t |t | gt |t |gg}t |t ||jS )zCalculate the rotated sigma matrix (two dimensional matrix).

    Args:
        sig_x (float):
        sig_y (float):
        theta (float): Radian measurement.

    Returns:
        ndarray: Rotated sigma matrix.
       r   )nparraycossindotT)sig_xsig_ythetad_matrixZu_matrix r   b/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/basicsr/data/degradations.pysigma_matrix2   s    0r   c                 C   sj   t |  d d | d d }t ||\}}t || |  df|| |  df| | d}|||fS )a&  Generate the mesh grid, centering at zero.

    Args:
        kernel_size (int):

    Returns:
        xy (ndarray): with the shape (kernel_size, kernel_size, 2)
        xx (ndarray): with the shape (kernel_size, kernel_size)
        yy (ndarray): with the shape (kernel_size, kernel_size)
    r         ?   )r   ZarangeZmeshgridZhstackZreshape)kernel_sizeaxxxyyZxyr   r   r   	mesh_grid    s    r   c              	   C   s2   t j| }t dt t ||| d }|S )a.  Calculate PDF of the bivariate Gaussian distribution.

    Args:
        sigma_matrix (ndarray): with the shape (2, 2)
        grid (ndarray): generated by :func:`mesh_grid`,
            with the shape (K, K, 2), K is the kernel size.

    Returns:
        kernel (ndarrray): un-normalized kernel.
          r   )r   linalginvexpsumr
   )sigma_matrixgridinverse_sigmakernelr   r   r   pdf22   s    "r#   c                 C   s4   t ddgddgddgg}t|| }||}|S )aO  Calculate the CDF of the standard bivariate Gaussian distribution.
        Used in skewed Gaussian distribution.

    Args:
        d_matrix (ndarrasy): skew matrix.
        grid (ndarray): generated by :func:`mesh_grid`,
            with the shape (K, K, 2), K is the kernel size.

    Returns:
        cdf (ndarray): skewed cdf.
    r   r   )r   r   r
   cdf)r   r    rvr$   r   r   r   cdf2B   s    
r&   Tc           	      C   sb   |du rt | \}}}|r:t|d dgd|d gg}nt|||}t||}|t| }|S )a  Generate a bivariate isotropic or anisotropic Gaussian kernel.

    In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.

    Args:
        kernel_size (int):
        sig_x (float):
        sig_y (float):
        theta (float): Radian measurement.
        grid (ndarray, optional): generated by :func:`mesh_grid`,
            with the shape (K, K, 2), K is the kernel size. Default: None
        isotropic (bool):

    Returns:
        kernel (ndarray): normalized kernel.
    Nr   r   )r   r   r   r   r#   r   )	r   r   r   r   r    	isotropic_r   r"   r   r   r   bivariate_GaussianT   s     
r)   c                 C   s   |du rt | \}}}|r:t|d dgd|d gg}nt|||}tj|}	tdttt	||	| d| }
|
t|
 }
|
S )a  Generate a bivariate generalized Gaussian kernel.
        Described in `Parameter Estimation For Multivariate Generalized
        Gaussian Distributions`_
        by Pascal et. al (2013).

    In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.

    Args:
        kernel_size (int):
        sig_x (float):
        sig_y (float):
        theta (float): Radian measurement.
        beta (float): shape parameter, beta = 1 is the normal distribution.
        grid (ndarray, optional): generated by :func:`mesh_grid`,
            with the shape (K, K, 2), K is the kernel size. Default: None

    Returns:
        kernel (ndarray): normalized kernel.

    .. _Parameter Estimation For Multivariate Generalized Gaussian
    Distributions: https://arxiv.org/abs/1302.6498
    Nr   r   r   )
r   r   r   r   r   r   r   powerr   r
   r   r   r   r   betar    r'   r(   r   r!   r"   r   r   r   bivariate_generalized_Gaussianp   s     *r-   c              
   C   s   |du rt | \}}}|r:t|d dgd|d gg}nt|||}tj|}	tttt	||	| d|d }
|
t|
 }
|
S )a  Generate a plateau-like anisotropic kernel.
    1 / (1+x^(beta))

    Ref: https://stats.stackexchange.com/questions/203629/is-there-a-plateau-shaped-distribution

    In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.

    Args:
        kernel_size (int):
        sig_x (float):
        sig_y (float):
        theta (float): Radian measurement.
        beta (float): shape parameter, beta = 1 is the normal distribution.
        grid (ndarray, optional): generated by :func:`mesh_grid`,
            with the shape (K, K, 2), K is the kernel size. Default: None

    Returns:
        kernel (ndarray): normalized kernel.
    Nr   r   r   )
r   r   r   r   r   r   Z
reciprocalr*   r   r
   r+   r   r   r   bivariate_plateau   s     *r.   c                 C   s  | d dksJ d|d |d k s,J dt j|d |d }|du r|d |d k sbJ d|d |d k szJ dt j|d |d }t j|d |d }n|}d}t| ||||d	}	|d
ur|d |d k sJ dt jj|d |d |	jd}
|	|
 }	|	t |	 }	|	S )a  Randomly generate bivariate isotropic or anisotropic Gaussian kernels.

    In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.

    Args:
        kernel_size (int):
        sigma_x_range (tuple): [0.6, 5]
        sigma_y_range (tuple): [0.6, 5]
        rotation range (tuple): [-math.pi, math.pi]
        noise_range(tuple, optional): multiplicative kernel noise,
            [0.75, 1.25]. Default: None

    Returns:
        kernel (ndarray):
    r   r   "Kernel size must be an odd number.r   Wrong sigma_x_range.FWrong sigma_y_range.Wrong rotation_range.r'   NWrong noise range.size)r   randomuniformr)   shaper   )r   sigma_x_rangesigma_y_rangerotation_rangenoise_ranger'   sigma_xsigma_yrotationr"   noiser   r   r   random_bivariate_Gaussian   s"    
rB   c                 C   sR  | d dksJ d|d |d k s,J dt j|d |d }|du r|d |d k sbJ d|d |d k szJ dt j|d |d }t j|d |d }	n|}d}	t j d	k rt j|d d}
nt jd|d }
t| |||	|
|d
}|dur@|d |d k sJ dt jj|d |d |jd}|| }|t | }|S )a  Randomly generate bivariate generalized Gaussian kernels.

    In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.

    Args:
        kernel_size (int):
        sigma_x_range (tuple): [0.6, 5]
        sigma_y_range (tuple): [0.6, 5]
        rotation range (tuple): [-math.pi, math.pi]
        beta_range (tuple): [0.5, 8]
        noise_range(tuple, optional): multiplicative kernel noise,
            [0.75, 1.25]. Default: None

    Returns:
        kernel (ndarray):
    r   r   r/   r   r0   Fr1   r2         ?r3   Nr4   r5   )r   r7   r8   r-   r9   r   r   r:   r;   r<   Z
beta_ranger=   r'   r>   r?   r@   r,   r"   rA   r   r   r   %random_bivariate_generalized_Gaussian   s(    
rE   c                 C   sR  | d dksJ d|d |d k s,J dt j|d |d }|du r|d |d k sbJ d|d |d k szJ dt j|d |d }t j|d |d }	n|}d}	t j d	k rt j|d d}
nt jd|d }
t| |||	|
|d
}|dur@|d |d k sJ dt jj|d |d |jd}|| }|t | }|S )a   Randomly generate bivariate plateau kernels.

    In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.

    Args:
        kernel_size (int):
        sigma_x_range (tuple): [0.6, 5]
        sigma_y_range (tuple): [0.6, 5]
        rotation range (tuple): [-math.pi/2, math.pi/2]
        beta_range (tuple): [1, 4]
        noise_range(tuple, optional): multiplicative kernel noise,
            [0.75, 1.25]. Default: None

    Returns:
        kernel (ndarray):
    r   r   r/   r   r0   Fr1   r2   rC   r3   Nr4   r5   )r   r7   r8   r.   r9   r   rD   r   r   r   random_bivariate_plateau  s(    
rF      )g333333?   )rC      c	              	   C   s   t | |d }	|	dkr.t|||||dd}
n|	dkrLt|||||dd}
n~|	dkrlt||||||dd}
n^|	dkrt||||||dd}
n>|	d	krt|||||d
dd}
n|	dkrt|||||d
dd}
|
S )a  Randomly generate mixed kernels.

    Args:
        kernel_list (tuple): a list name of kernel types,
            support ['iso', 'aniso', 'skew', 'generalized', 'plateau_iso',
            'plateau_aniso']
        kernel_prob (tuple): corresponding kernel probability for each
            kernel type
        kernel_size (int):
        sigma_x_range (tuple): [0.6, 5]
        sigma_y_range (tuple): [0.6, 5]
        rotation range (tuple): [-math.pi, math.pi]
        beta_range (tuple): [0.5, 8]
        noise_range(tuple, optional): multiplicative kernel noise,
            [0.75, 1.25]. Default: None

    Returns:
        kernel (ndarray):
    r   ZisoT)r=   r'   ZanisoFZgeneralized_isoZgeneralized_anisoZplateau_isoNZplateau_aniso)r7   choicesrB   rE   rF   )Zkernel_listZkernel_probr   r:   r;   r<   Zbetag_rangeZbetap_ranger=   Zkernel_typer"   r   r   r   random_mixed_kernelsG  sL    rK   ignore)divideinvalidc                    s   d dksJ dt  fddg} d dt j  |d d d d f< |t | }|kr| d }t |||f||ff}|S )aM  2D sinc filter, ref: https://dsp.stackexchange.com/questions/58301/2-d-circularly-symmetric-low-pass-filter

    Args:
        cutoff (float): cutoff frequency in radians (pi is max)
        kernel_size (int): horizontal and vertical size, must be odd.
        pad_to (int): pad kernel size to desired size, must be odd or zero.
    r   r   r/   c              
      st    t  t| d d  d |d d  d    dtj t| d d  d |d d  d    S )Nr   r   )r   Zj1r   sqrtpi)xycutoffr   r   r   <lambda>  s   &&z)circular_lowpass_kernel.<locals>.<lambda>   )r   ZfromfunctionrP   r   pad)rT   r   Zpad_tor"   Zpad_sizer   rS   r   circular_lowpass_kernel  s    *rX   
   Fc                 C   sb   |rBt t jj| jdd  | d }t j|ddjddd}nt t jj| j | d }|S )a/  Generate Gaussian noise.

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        sigma (float): Noise scale (measured in range 255). Default: 10.

    Returns:
        (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
            float32.
    r   r        o@Zaxis   )r   float32r7   randnr9   Zexpand_dimsrepeat)imgsigma
gray_noiserA   r   r   r   generate_gaussian_noise  s
    $rc   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S )a*  Add Gaussian noise.

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        sigma (float): Noise scale (measured in range 255). Default: 10.

    Returns:
        (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
            float32.
    rZ   r      r   )rc   r   clipround)r`   ra   re   roundsrb   rA   outr   r   r   add_gaussian_noise  s    ri   c           
      C   s   |   \}}}}t|ttfs4||  dddd}t|ttfrL|dk}n||ddd}t|dk}|rtj|   dd | j| j	d| d }||d||}tj|   | j| j	d| d }	|r|	d|  ||  }	|	S )  Add Gaussian noise (PyTorch version).

    Args:
        img (Tensor): Shape (b, c, h, w), range[0, 1], float32.
        scale (float | Tensor): Noise scale. Default: 1.0.

    Returns:
        (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
            float32.
    r   r   r   rV   dtypedevicerZ   )
r6   
isinstancefloatintviewtorchr   r^   rl   rm   )
r`   ra   rb   br(   hwcal_gray_noise
noise_grayrA   r   r   r   generate_gaussian_noise_pt  s    
*"rx   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S )rj   rZ   r   rd   r   )rx   rr   clamprf   )r`   ra   rb   re   rg   rA   rh   r   r   r   add_gaussian_noise_pt  s    rz   r   rY   c                 C   s:   t j|d |d }t j |k r*d}nd}t| ||S Nr   r   TF)r   r7   r8   rc   r`   sigma_range	gray_probra   rb   r   r   r   random_generate_gaussian_noise  s
    r   r   r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S NrZ   r   rd   r   )r   r   re   rf   r`   r~   r   re   rg   rA   rh   r   r   r   random_add_gaussian_noise  s    r   c                 C   sd   t j| d| j| jd|d |d   |d  }t j| d| j| jd}||k  }t| ||S Nr   rk   r   )rr   randr6   rl   rm   ro   rx   r}   r   r   r   !random_generate_gaussian_noise_pt  s    r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S r   )r   rr   ry   rf   r   r   r   r   random_add_gaussian_noise_pt!  s    r   r   c                 C   s   |rt | t j} t| d  ddd } tt| }dtt	| }t
tj| | t| }||  }|rtj|ddddtjf ddd}|| S )a  Generate poisson noise.

    Ref: https://github.com/scikit-image/scikit-image/blob/main/skimage/util/noise.py#L37-L219

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        scale (float): Noise scale. Default: 1.0.
        gray_noise (bool): Whether generate gray noise. Default: False.

    Returns:
        (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
            float32.
    rZ   r   rd   r   Nr\   r[   )cv2ZcvtColorZCOLOR_BGR2GRAYr   re   rf   lenuniqueceillog2r]   r7   poissonro   r_   Znewaxis)r`   scalerb   valsrh   rA   r   r   r   generate_poisson_noise0  s    $r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S )aZ  Add poisson noise.

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        scale (float): Noise scale. Default: 1.0.
        gray_noise (bool): Whether generate gray noise. Default: False.

    Returns:
        (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
            float32.
    rZ   r   rd   r   )r   r   re   rf   r`   r   re   rg   rb   rA   rh   r   r   r   add_poisson_noiseK  s    r   c                    s     \}}}}t|ttfr(|dk}n||ddd}t|dk}|rt ddtd 	 ddd fddt
|D }dd |D }||ddd}	t|	 |	 }
|
 }||d	||}t d 	 ddd   fd
dt
|D }dd |D } ||ddd}	t |	 |	 }
|
  }|r\|d|  ||  }t|ttfs|||ddd}|| S )a  Generate a batch of poisson noise (PyTorch version)

    Args:
        img (Tensor): Input image, shape (b, c, h, w), range [0, 1], float32.
        scale (float | Tensor): Noise scale. Number or Tensor with shape (b).
            Default: 1.0.
        gray_noise (float | Tensor): 0-1 number or Tensor with shape (b).
            0 for False, 1 for True. Default: 0.

    Returns:
        (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
            float32.
    r   r   )Znum_output_channelsrZ   rd   c                    s2   g | ]*}t t |d d d d d d f qS Nr   rr   r   .0i)img_grayr   r   
<listcomp>{      z-generate_poisson_noise_pt.<locals>.<listcomp>c                 S   s    g | ]}d t t | qS r   r   r   r   r   r   r   r   r   r   |  r   r\   c                    s2   g | ]*}t t |d d d d d d f qS r   r   r   )r`   r   r   r     r   c                 S   s    g | ]}d t t | qS r   r   r   r   r   r   r     r   )r6   rn   ro   rp   rq   rr   r   r   ry   rf   rangeZ
new_tensorr   expand)r`   r   rb   rs   r(   rt   ru   rv   Z	vals_listr   rh   rw   rA   r   )r`   r   r   generate_poisson_noise_ptb  s2    
r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S )a  Add poisson noise to a batch of images (PyTorch version).

    Args:
        img (Tensor): Input image, shape (b, c, h, w), range [0, 1], float32.
        scale (float | Tensor): Noise scale. Number or Tensor with shape (b).
            Default: 1.0.
        gray_noise (float | Tensor): 0-1 number or Tensor with shape (b).
            0 for False, 1 for True. Default: 0.

    Returns:
        (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
            float32.
    rZ   r   rd   r   )r   rr   ry   rf   r   r   r   r   add_poisson_noise_pt  s    r   c                 C   s:   t j|d |d }t j |k r*d}nd}t| ||S r|   )r   r7   r8   r   r`   scale_ranger   r   rb   r   r   r   random_generate_poisson_noise  s
    r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S r   )r   r   re   rf   r`   r   r   re   rg   rA   rh   r   r   r   random_add_poisson_noise  s    r   c                 C   sd   t j| d| j| jd|d |d   |d  }t j| d| j| jd}||k  }t| ||S r   )rr   r   r6   rl   rm   ro   r   r   r   r   r    random_generate_poisson_noise_pt  s    r   c                 C   sd   t | ||}| | }|r8|r8t|d  ddd }n(|rLt|dd}n|r`|d  d }|S r   )r   rr   ry   rf   r   r   r   r   random_add_poisson_noise_pt  s    r   Z   c                 C   sL   t | dd} ttj|g}td| d |\}}t t|dd } | S )ag  Add JPG compression artifacts.

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        quality (float): JPG compression quality. 0 for lowest quality, 100 for
            best quality. Default: 90.

    Returns:
        (Numpy array): Returned image after JPG, shape (h, w, c), range[0, 1],
            float32.
    r   r   z.jpgrZ   )r   re   rp   r   ZIMWRITE_JPEG_QUALITYZimencoder]   Zimdecode)r`   qualityZencode_paramr(   Zencimgr   r   r   add_jpg_compression  s
    r   r   d   c                 C   s    t j|d |d }t| |S )a  Randomly add JPG compression artifacts.

    Args:
        img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
        quality_range (tuple[float] | list[float]): JPG compression quality
            range. 0 for lowest quality, 100 for best quality.
            Default: (90, 100).

    Returns:
        (Numpy array): Returned image after JPG, shape (h, w, c), range[0, 1],
            float32.
    r   r   )r   r7   r8   r   )r`   Zquality_ranger   r   r   r   random_add_jpg_compression  s    r   )NT)NT)NT)NT)NT)NT)r   )rY   F)rY   TFF)rY   r   )rY   r   TF)r{   r   )r   r   TF)r{   r   )r   r   TF)r   F)r   TFF)r   r   )r   TFr   )r   r   )r   r   TF)r   r   )r   r   TF)r   )r   ),r   mathnumpyr   r7   rr   Zscipyr   Zscipy.statsr   Z(torchvision.transforms.functional_tensorr   r   r   r#   r&   r)   r-   r.   rB   rE   rF   rP   rK   ZseterrrX   rc   ri   rx   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sf   

#
$  
1  
9  
6
>



 

	





0

	



