a
    dC                     @   s   d dl mZmZmZmZmZmZ d dlZd dlmZ d dl	m
Z
 d dlmZmZmZ d dlmZ d dlmZ d dlmZ d d	lmZmZ esd
dgZG dd deZG dd deZdS )    )AnyListOptionalSequenceTupleUnionN)Tensor)Literal)_multiscale_ssim_update_ssim_check_inputs_ssim_update)Metric)dim_zero_cat)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPE%StructuralSimilarityIndexMeasure.plot/MultiScaleStructuralSimilarityIndexMeasure.plotc                       s  e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< d	Ze
ed
< ee ed< ee ed< d eee
ee
 f eeee f ed eee
ee
e
f f  e
e
eeedd fddZeeddddZeeeeef f dddZd!eeeee f  ee edddZ  ZS )" StructuralSimilarityIndexMeasurea4	  Compute Structural Similarity Index Measure (SSIM_).

    As input to ``forward`` and ``update`` the metric accepts the following input

    - ``preds`` (:class:`~torch.Tensor`): Predictions from model
    - ``target`` (:class:`~torch.Tensor`): Ground truth values

    As output of `forward` and `compute` the metric returns the following output

    - ``ssim`` (:class:`~torch.Tensor`): if ``reduction!='none'`` returns float scalar tensor with average SSIM value
      over sample else returns tensor of shape ``(N,)`` with SSIM values per sample

    Args:
        preds: estimated image
        target: ground truth image
        gaussian_kernel: If ``True`` (default), a gaussian kernel is used, if ``False`` a uniform kernel is used
        sigma: Standard deviation of the gaussian kernel, anisotropic kernels are possible.
            Ignored if a uniform kernel is used
        kernel_size: the size of the uniform kernel, anisotropic kernels are possible.
            Ignored if a Gaussian kernel is used
        reduction: a method to reduce metric score over individual batch scores

            - ``'elementwise_mean'``: takes the mean
            - ``'sum'``: takes the sum
            - ``'none'`` or ``None``: no reduction will be applied

        data_range:
            the range of the data. If None, it is determined from the data (max - min). If a tuple is provided then
            the range is calculated as the difference and input is clamped between the values.
        k1: Parameter of SSIM.
        k2: Parameter of SSIM.
        return_full_image: If true, the full ``ssim`` image is returned as a second argument.
            Mutually exclusive with ``return_contrast_sensitivity``
        return_contrast_sensitivity: If true, the constant term is returned as a second argument.
            The luminance term can be obtained with luminance=ssim/contrast
            Mutually exclusive with ``return_full_image``
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Example:
        >>> import torch
        >>> from torchmetrics.image import StructuralSimilarityIndexMeasure
        >>> preds = torch.rand([3, 3, 256, 256])
        >>> target = preds * 0.75
        >>> ssim = StructuralSimilarityIndexMeasure(data_range=1.0)
        >>> ssim(preds, target)
        tensor(0.9219)

    Thigher_is_betteris_differentiableFfull_state_update        plot_lower_bound      ?plot_upper_boundpredstarget      ?   elementwise_meanN{Gz?Q?r    sumnoneN)gaussian_kernelsigmakernel_size	reduction
data_rangek1k2return_full_imagereturn_contrast_sensitivitykwargsreturnc
                    s   t  jf i |
 d}||vr2td| d| |dv rR| jdtddd n| jdg d	d | jd
tddd |	s|r| jdg d	d || _|| _|| _|| _	|| _
|| _|| _|| _|	| _d S )Nr#   $Argument `reduction` must be one of 
, but got r    r$   
similarityr   r$   defaultZdist_reduce_fxcattotalimage_return)super__init__
ValueError	add_statetorchtensorr&   r'   r(   r)   r*   r+   r,   r-   r.   )selfr&   r'   r(   r)   r*   r+   r,   r-   r.   r/   valid_reduction	__class__ `/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/image/ssim.pyr;   Y   s&    z)StructuralSimilarityIndexMeasure.__init__r   r   r0   c                 C   s   t ||\}}t||| j| j| j| j| j| j| j| j	
}t
|trL|\}}n|}| j	s\| jrh| j| | jdv r|  j| 7  _|  j|jd 7  _n| j| dS )*Update state with predictions and targets.r3   r   N)r   r   r&   r'   r(   r*   r+   r,   r-   r.   
isinstancetupler9   appendr)   r4   r$   r8   shape)r@   r   r   Zsimilarity_packr4   imagerD   rD   rE   update   s,    


z'StructuralSimilarityIndexMeasure.updater0   c                 C   sV   | j dkr| j| j }n| j dkr*| j}n
t| j}| js@| jrRt| j}||fS |S )zCompute SSIM over state.r    r$   )r)   r4   r8   r   r.   r-   r9   )r@   r4   r9   rD   rD   rE   compute   s    



z(StructuralSimilarityIndexMeasure.computevalaxr0   c                 C   s   |  ||S )a  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value
            >>> import torch
            >>> from torchmetrics.image import StructuralSimilarityIndexMeasure
            >>> preds = torch.rand([3, 3, 256, 256])
            >>> target = preds * 0.75
            >>> metric = StructuralSimilarityIndexMeasure(data_range=1.0)
            >>> metric.update(preds, target)
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.image import StructuralSimilarityIndexMeasure
            >>> preds = torch.rand([3, 3, 256, 256])
            >>> target = preds * 0.75
            >>> metric = StructuralSimilarityIndexMeasure(data_range=1.0)
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(preds, target))
            >>> fig_, ax_ = metric.plot(values)

        Z_plotr@   rQ   rR   rD   rD   rE   plot   s    ,r   )	Tr   r   r    Nr!   r"   FF)NN)__name__
__module____qualname____doc__r   bool__annotations__r   r   r   floatr   r   r   r   r   intr	   r   r   r   r;   rM   rO   r   r   rU   __classcell__rD   rD   rB   rE   r      sJ   
1         ' r   c                       s  e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< d	Ze
ed
< ee ed< ee ed< d$eeeee f ee
ee
 f ed eee
ee
e
f f  e
e
ee
df ed edd fddZeeddddZeddd Zd%eeeee f  ee ed!d"d#Z  ZS )&*MultiScaleStructuralSimilarityIndexMeasurea  Compute `MultiScaleSSIM`_, Multi-scale Structural Similarity Index Measure.

    This metric is is a generalization of Structural Similarity Index Measure by incorporating image details at
    different resolution scores.

    As input to ``forward`` and ``update`` the metric accepts the following input

    - ``preds`` (:class:`~torch.Tensor`): Predictions from model
    - ``target`` (:class:`~torch.Tensor`): Ground truth values

    As output of `forward` and `compute` the metric returns the following output

    - ``msssim`` (:class:`~torch.Tensor`): if ``reduction!='none'`` returns float scalar tensor with average MSSSIM
      value over sample else returns tensor of shape ``(N,)`` with SSIM values per sample

    Args:
        gaussian_kernel: If ``True`` (default), a gaussian kernel is used, if false a uniform kernel is used
        kernel_size: size of the gaussian kernel
        sigma: Standard deviation of the gaussian kernel
        reduction: a method to reduce metric score over labels.

            - ``'elementwise_mean'``: takes the mean
            - ``'sum'``: takes the sum
            - ``'none'`` or ``None``: no reduction will be applied

        data_range:
            the range of the data. If None, it is determined from the data (max - min). If a tuple is provided then
            the range is calculated as the difference and input is clamped between the values.
            The ``data_range`` must be given when ``dim`` is not None.
        k1: Parameter of structural similarity index measure.
        k2: Parameter of structural similarity index measure.
        betas: Exponent parameters for individual similarities and contrastive sensitivies returned by different image
            resolutions.
        normalize: When MultiScaleStructuralSimilarityIndexMeasure loss is used for training, it is desirable to use
            normalizes to improve the training stability. This `normalize` argument is out of scope of the original
            implementation [1], and it is adapted from https://github.com/jorge-pessoa/pytorch-msssim instead.
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Return:
        Tensor with Multi-Scale SSIM score

    Raises:
        ValueError:
            If ``kernel_size`` is not an int or a Sequence of ints with size 2 or 3.
        ValueError:
            If ``betas`` is not a tuple of floats with lengt 2.
        ValueError:
            If ``normalize`` is neither `None`, `ReLU` nor `simple`.

    Example:
        >>> from torchmetrics.image import MultiScaleStructuralSimilarityIndexMeasure
        >>> import torch
        >>> gen = torch.manual_seed(42)
        >>> preds = torch.rand([3, 3, 256, 256], generator=torch.manual_seed(42))
        >>> target = preds * 0.75
        >>> ms_ssim = MultiScaleStructuralSimilarityIndexMeasure(data_range=1.0)
        >>> ms_ssim(preds, target)
        tensor(0.9627)

    Tr   r   Fr   r   r   r   r   r   r   r   r   r    Nr!   r"   gǺ?g48EG?ga4?g??g9EGr?relur#   .)ra   simpleN)r&   r(   r'   r)   r*   r+   r,   betas	normalizer/   r0   c
                    sX  t  jf i |
 d}||vr2td| d| |dv rR| jdtddd n| jdg d	d | jd
tddd t|ttfstd| t|trt	|dvst
dd |D std| || _|| _|| _|| _|| _|| _|| _t|tstdt|tr0t
dd |D s0td|| _|	rN|	dvrNtd|	| _d S )Nr#   r1   r2   r3   r4   r   r$   r5   r7   r8   zRArgument `kernel_size` expected to be an sequence or an int, or a single int. Got )      c                 s   s   | ]}t |tV  qd S N)rH   r]   ).0ksrD   rD   rE   	<genexpr>B      zFMultiScaleStructuralSimilarityIndexMeasure.__init__.<locals>.<genexpr>ztArgument `kernel_size` expected to be an sequence of size 2 or 3 where each element is an int, or a single int. Got z3Argument `betas` is expected to be of a type tuple.c                 s   s   | ]}t |tV  qd S rg   )rH   r\   )rh   betarD   rD   rE   rj   R  rk   z5Argument `betas` is expected to be a tuple of floats.)ra   rb   zNArgument `normalize` to be expected either `None` or one of 'relu' or 'simple')r:   r;   r<   r=   r>   r?   rH   r   r]   lenallr&   r'   r(   r)   r*   r+   r,   rI   rc   rd   )r@   r&   r(   r'   r)   r*   r+   r,   rc   rd   r/   rA   rB   rD   rE   r;   #  sJ    

 z3MultiScaleStructuralSimilarityIndexMeasure.__init__rF   c                 C   sz   t ||\}}t||| j| j| j| j| j| j| j| j	
}| j
dv rP| j| n|  j| 7  _|  j|jd 7  _dS )rG   r%   Nr   N)r   r
   r&   r'   r(   r*   r+   r,   rc   rd   r)   r4   rJ   r$   r8   rK   )r@   r   r   r4   rD   rD   rE   rM   Y  s"    
z1MultiScaleStructuralSimilarityIndexMeasure.updaterN   c                 C   s0   | j dv rt| jS | j dkr$| jS | j| j S )zCompute MS-SSIM over state.ro   r$   )r)   r   r4   r8   )r@   rD   rD   rE   rO   p  s
    


z2MultiScaleStructuralSimilarityIndexMeasure.computerP   c                 C   s   |  ||S )a\  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value
            >>> from torchmetrics.image import MultiScaleStructuralSimilarityIndexMeasure
            >>> import torch
            >>> preds = torch.rand([3, 3, 256, 256], generator=torch.manual_seed(42))
            >>> target = preds * 0.75
            >>> metric = MultiScaleStructuralSimilarityIndexMeasure(data_range=1.0)
            >>> metric.update(preds, target)
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torchmetrics.image import MultiScaleStructuralSimilarityIndexMeasure
            >>> import torch
            >>> preds = torch.rand([3, 3, 256, 256], generator=torch.manual_seed(42))
            >>> target = preds * 0.75
            >>> metric = MultiScaleStructuralSimilarityIndexMeasure(data_range=1.0)
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(preds, target))
            >>> fig_, ax_ = metric.plot(values)

        rS   rT   rD   rD   rE   rU   x  s    ,r   )	Tr   r   r    Nr!   r"   r`   ra   )NN)rV   rW   rX   rY   r   rZ   r[   r   r   r   r\   r   r   r   r   r]   r   r	   r   r   r   r;   rM   rO   r   r   rU   r^   rD   rD   rB   rE   r_      sJ   
=         
6	 r_   )typingr   r   r   r   r   r   r>   r   Ztyping_extensionsr	   Z"torchmetrics.functional.image.ssimr
   r   r   Ztorchmetrics.metricr   Ztorchmetrics.utilities.datar   Ztorchmetrics.utilities.importsr   Ztorchmetrics.utilities.plotr   r   Z__doctest_skip__r   r_   rD   rD   rD   rE   <module>   s     ?