
    i$                         d dl mZ d dl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mZmZ d dlmZ d dlmZmZ d d	lmZmZmZ d d
lmZmZ esdgZererddZer ee      s	ddgZnddgZ G d de      Zy)    )Sequence)AnyOptionalUnionN)Tensor)Literal)_ARNIQA_TYPE_REGRESSOR_DATASET_arniqa_compute_arniqa_update_NoTrainArniqa)Metric)_SKIP_SLOW_DOCTEST_try_proceed_with_timeout)_MATPLOTLIB_AVAILABLE_TORCH_GREATER_EQUAL_2_2_TORCHVISION_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEzARNIQA.plotc                      t        d       y )Nkoniq10kregressor_dataset)r	        n/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/image/arniqa.py_download_arniqar   &   s
    *-r   ARNIQAc                       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d<   eed<   dZeed<   	 	 	 	 ddeded   dedededdf fdZdeddfdZdefdZ	 ddeeeee   f      dee   defdZ xZS ) r   a  ARNIQA: leArning distoRtion maNifold for Image Quality Assessment metric.

    `ARNIQA`_ is a No-Reference Image Quality Assessment metric that predicts the technical quality of an image with
    a high correlation with human opinions. ARNIQA consists of an encoder and a regressor. The encoder is a ResNet-50
    model trained in a self-supervised way to model the image distortion manifold to generate similar representation for
    images with similar distortions, regardless of the image content. The regressor is a linear model trained on IQA
    datasets using the ground-truth quality scores. ARNIQA extracts the features from the full- and half-scale versions
    of the input image and then outputs a quality score in the [0, 1] range, where higher is better.

    The input image is expected to have shape ``(N, 3, H, W)``. The image should be in the [0, 1] range if `normalize`
    is set to ``True``, otherwise it should be normalized with the ImageNet mean and standard deviation.

    .. note::
        Using this metric requires you to have ``torchvision`` package installed. Either install as
        ``pip install torchmetrics[image]`` or ``pip install torchvision``.

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

    - ``img`` (:class:`~torch.Tensor`): tensor with images of shape ``(N, 3, H, W)``

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

    - ``arniqa`` (:class:`~torch.Tensor`): tensor with ARNIQA score. If `reduction` is set to ``none``, the output will
      have shape ``(N,)``, otherwise it will be a scalar tensor. Tensor values are in the [0, 1] range, where higher
      is better.

    Args:
        img: the input image
        regressor_dataset: dataset used for training the regressor. Choose between [``koniq10k``, ``kadid10k``].
            ``koniq10k`` corresponds to the `KonIQ-10k`_ dataset, which consists of real-world images with authentic
            distortions. ``kadid10k`` corresponds to the `KADID-10k`_ dataset, which consists of images with
            synthetically generated distortions.
        reduction: indicates how to reduce over the batch dimension. Choose between [``sum``, ``mean``, ``none``].
        normalize: by default this is ``True`` meaning that the input is expected to be in the [0, 1] range. If set
            to ``False`` will instead expect input to be already normalized with the ImageNet mean and standard
            deviation.
        autocast: if ``True``, metric will convert model to mixed precision before running forward pass.
        kwargs: additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ModuleNotFoundError:
            If ``torchvision`` package is not installed
        ValueError:
            If ``regressor_dataset`` is not in [``"kadid10k"``, ``"koniq10k"``]
        ValueError:
            If ``reduction`` is not in [``"sum"``, ``"mean"``, ``"none"``]
        ValueError:
            If ``normalize`` is not a bool
        ValueError:
            If the input image is not a valid image tensor with shape [N, 3, H, W].
        ValueError:
            If the input image values are not in the [0, 1] range when ``normalize`` is set to ``True``

    Examples:
        >>> from torch import rand
        >>> from torchmetrics.image.arniqa import ARNIQA
        >>> img = rand(8, 3, 224, 224)
        >>> # Non-normalized input
        >>> metric = ARNIQA(regressor_dataset='koniq10k', normalize=True)
        >>> metric(img)
        tensor(0.5308)

        >>> from torch import rand
        >>> from torchmetrics.image.arniqa import ARNIQA
        >>> from torchvision.transforms import Normalize
        >>> img = rand(8, 3, 224, 224)
        >>> img = Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])(img)
        >>> # Normalized input
        >>> metric = ARNIQA(regressor_dataset='koniq10k', normalize=False)
        >>> metric(img)
        tensor(0.5065)

    Tis_differentiablehigher_is_betterFfull_state_update        plot_lower_boundg      ?plot_upper_bound
sum_scores
num_scoresmodelfeature_networkr   	reduction)summeannone	normalizeautocastkwargsreturnNc                    t        |   di | t        st        d      t        st        d      t        |      | _        d}||vrt        d| d|       || _	        t        |t              st        d|       || _        || _        | j                  dt        j                   d	      d
       | j                  dt        j                   d	      d
       y )Nz'ARNIQA metric requires PyTorch >= 2.2.0zARNIQA metric requires that torchvision is installed. Either install as `pip install torchmetrics[image]` or `pip install torchvision`.r   )r,   r+   r-   z$Argument `reduction` must be one of z
, but got z.Argument `normalize` should be a bool but got r&   r#   r+   )dist_reduce_fxr'   r   )super__init__r   RuntimeErrorr   ModuleNotFoundErrorr   r(   
ValueErrorr*   
isinstanceboolr.   r/   	add_statetorchtensor)selfr   r*   r.   r/   r0   valid_reduction	__class__s          r   r5   zARNIQA.__init__   s     	"6"'HII%%e 
 $6GH
1O+COCTT^_h^ijkk")T*Mi[YZZ" |U\\#%6uM|U\\#%6uMr   imgc                     t        || j                  | j                  | j                        \  }}| xj                  |j                         z  c_        | xj                  |z  c_        y)z)Update internal states with arniqa score.)r(   r.   r/   N)r   r(   r.   r/   r&   r+   r'   )r>   rA   lossr'   s       r   updatezARNIQA.update   sH    )#TZZ4>>dhdqdqrj488:%:%r   c                 X    t        | j                  | j                  | j                        S )zCompute final arniqa metric.)r   r&   r'   r*   )r>   s    r   computezARNIQA.compute   s    tPPr   valaxc                 &    | j                  ||      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.arniqa import ARNIQA
            >>> metric = ARNIQA(regressor_dataset='koniq10k')
            >>> metric.update(torch.rand(8, 3, 224, 224))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.image.arniqa import ARNIQA
            >>> metric = ARNIQA(regressor_dataset='koniq10k')
            >>> values = [ ]
            >>> for _ in range(3):
            ...     values.append(metric(torch.rand(8, 3, 224, 224)))
            >>> fig_, ax_ = metric.plot(values)

        )_plot)r>   rG   rH   s      r   plotzARNIQA.plot   s    P zz#r""r   )r   r,   TF)NN)__name__
__module____qualname____doc__r    r:   __annotations__r!   r"   r$   floatr%   r   r)   strr
   r   r   r5   rD   rF   r   r   r   r   r   rK   __classcell__)r@   s   @r   r   r   /   s   HT #t"!d!#t#!e!!e!"OS" 6@4: N2 N 01 N 	 N
  N  N 
 ND&& &T &Q Q
 _c(#E&(6*:":;<(#IQRZI[(#	(#r   )r1   N)collections.abcr   typingr   r   r   r<   r   typing_extensionsr   $torchmetrics.functional.image.arniqar	   r
   r   r   r   torchmetrics.metricr   torchmetrics.utilities.checksr   r   torchmetrics.utilities.importsr   r   r   torchmetrics.utilities.plotr   r   __doctest_skip__r   r   r   r   r   <module>r]      s|    % ' '   %  ' W r r @% 6. ";<L"M$m4 -0i#V i#r   