a
    d/                     @   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
mZ d dlmZmZ d dlmZ d dlmZ d dlmZmZ d d	lmZmZ erd d
lmZ ndZesddgZn
esdgZG dd deZdS )    )AnyDictListOptionalSequenceUnionN)Tensor)_fix_empty_tensors_input_validator)_iou_compute_iou_update)Metric)dim_zero_cat)_MATPLOTLIB_AVAILABLE_TORCHVISION_GREATER_EQUAL_0_8)_AX_TYPE_PLOT_OUT_TYPE)box_convertIntersectionOverUnionIntersectionOverUnion.plotc                       s:  e Zd ZU dZdZeed< dZee ed< dZ	eed< e
e ed< e
e ed< d	Zeed
< dZeed< d%eee eeedd fddZeeeedddZeeeedddZe
eeef  e
eeef  ddddZeedddZe
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 )'r   a  Computes Intersection Over Union (IoU).

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

    - ``preds`` (:class:`~List`): A list consisting of dictionaries each containing the key-values
      (each dictionary corresponds to a single image). Parameters that should be provided per dict:

        - ``boxes`` (:class:`~torch.Tensor`): float tensor of shape ``(num_boxes, 4)`` containing ``num_boxes``
          detection boxes of the format specified in the constructor.
          By default, this method expects ``(xmin, ymin, xmax, ymax)`` in absolute image coordinates.
        - labels: ``IntTensor`` of shape ``(num_boxes)`` containing 0-indexed detection classes for
          the boxes.

    - ``target`` (:class:`~List`): A list consisting of dictionaries each containing the key-values
      (each dictionary corresponds to a single image). Parameters that should be provided per dict:

        - ``boxes`` (:class:`~torch.Tensor`): float tensor of shape ``(num_boxes, 4)`` containing ``num_boxes`` ground
          truth boxes of the format specified in the constructor.
          By default, this method expects ``(xmin, ymin, xmax, ymax)`` in absolute image coordinates.
        - ``labels`` (:class:`~torch.Tensor`): integer tensor of shape ``(num_boxes)`` containing 0-indexed ground truth
          classes for the boxes.

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

    - ``iou_dict``: A dictionary containing the following key-values:

        - iou: (:class:`~torch.Tensor`)
        - iou/cl_{cl}: (:class:`~torch.Tensor`), if argument ``class metrics=True``

    Args:
        box_format:
            Input format of given boxes. Supported formats are ``[`xyxy`, `xywh`, `cxcywh`]``.
        iou_thresholds:
            Optional IoU thresholds for evaluation. If set to `None` the threshold is ignored.
        class_metrics:
            Option to enable per-class metrics for IoU. Has a performance impact.
        respect_labels:
            Ignore values from boxes that do not have the same label as the ground truth box. Else will compute Iou
                between all pairs of boxes.
        kwargs:
            Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Example::

        >>> import torch
        >>> from torchmetrics.detection import IntersectionOverUnion
        >>> preds = [
        ...    {
        ...        "boxes": torch.tensor([
        ...             [296.55, 93.96, 314.97, 152.79],
        ...             [298.55, 98.96, 314.97, 151.79]]),
        ...        "labels": torch.tensor([4, 5]),
        ...    }
        ... ]
        >>> target = [
        ...    {
        ...        "boxes": torch.tensor([[300.00, 100.00, 315.00, 150.00]]),
        ...        "labels": torch.tensor([5]),
        ...    }
        ... ]
        >>> metric = IntersectionOverUnion()
        >>> metric(preds, target)
        {'iou': tensor(0.8614)}

    Example::

        The metric can also return the score per class:

        >>> import torch
        >>> from torchmetrics.detection import IntersectionOverUnion
        >>> preds = [
        ...    {
        ...        "boxes": torch.tensor([
        ...             [296.55, 93.96, 314.97, 152.79],
        ...             [298.55, 98.96, 314.97, 151.79]]),
        ...        "labels": torch.tensor([4, 5]),
        ...    }
        ... ]
        >>> target = [
        ...    {
        ...        "boxes": torch.tensor([
        ...               [300.00, 100.00, 315.00, 150.00],
        ...               [300.00, 100.00, 315.00, 150.00]
        ...        ]),
        ...        "labels": torch.tensor([4, 5]),
        ...    }
        ... ]
        >>> metric = IntersectionOverUnion(class_metrics=True)
        >>> metric(preds, target)
        {'iou': tensor(0.7756), 'iou/cl_4': tensor(0.6898), 'iou/cl_5': tensor(0.8614)}

    Raises:
        ModuleNotFoundError:
            If torchvision is not installed with version 0.8.0 or newer.

    Fis_differentiableThigher_is_betterfull_state_updategroundtruth_labels
iou_matrixZiou	_iou_typeg      _invalid_valxyxyN)
box_formatiou_thresholdclass_metricsrespect_labelskwargsreturnc                    s   t  jf i | ts,td| j  dd}||vrLtd| d| || _|| _t	|t
sjtd|| _t	|t
std|| _| jdg d d	 | jd
g d d	 d S )NzMetric `z` requires that `torchvision` version 0.8.0 or newer is installed. Please install with `pip install torchvision>=0.8` or `pip install torchmetrics[detection]`.)r   ZxywhZcxcywhz,Expected argument `box_format` to be one of z	 but got z1Expected argument `class_metrics` to be a booleanz2Expected argument `respect_labels` to be a booleanr   )defaultZdist_reduce_fxr   )super__init__r   ModuleNotFoundErrorr   upper
ValueErrorr   r   
isinstanceboolr    r!   Z	add_state)selfr   r   r    r!   r"   Zallowed_box_formats	__class__ c/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/detection/iou.pyr&      s$    

zIntersectionOverUnion.__init__)argsr"   r#   c                  O   s   t | i |S N)r   r1   r"   r/   r/   r0   _iou_update_fn   s    z$IntersectionOverUnion._iou_update_fnc                  O   s   t | i |S r2   )r   r3   r/   r/   r0   _iou_compute_fn   s    z%IntersectionOverUnion._iou_compute_fn)predstargetr#   c           	      C   s   t ||dd t||D ]\}}| |d }| |d }| j|d  | ||| j| j}| jr|d 	d|d 	dk}| j|| < | j
| qdS )z*Update state with predictions and targets.T)Zignore_scoreboxeslabels   r   N)r
   zip_get_safe_item_valuesr   appendr4   r   r   r!   Z	unsqueezer   )	r,   r6   r7   ptZ	det_boxesZgt_boxesr   Zlabel_eqr/   r/   r0   update   s    zIntersectionOverUnion.update)r8   r#   c                 C   s(   t |}| dkr$t|| jdd}|S )Nr   r   )Zin_fmtZout_fmt)r	   numelr   r   )r,   r8   r/   r/   r0   r<      s    z+IntersectionOverUnion._get_safe_item_values)r#   c                 C   s&   t | jdkr"t| j  S g S )zJReturns a list of unique classes found in ground truth and detection data.r   )lenr   torchcatuniquetolistr,   r/   r/   r0   _get_gt_classes   s    z%IntersectionOverUnion._get_gt_classesc                    s   t  fdd jD d } j |i} jrt j}t|dkrT|	 
 ng }|D ]}t |t | }}t j jD ]H\}}	|dd|	|kf }
||
|
 jk  7 }||
|
 jk  7 }q| j d| || i q\|S )z@Computes IoU based on inputs passed in to ``update`` previously.c                    s   g | ]}|| j k qS r/   )r   ).0matrG   r/   r0   
<listcomp>       z1IntersectionOverUnion.compute.<locals>.<listcomp>r   Nz/cl_)rC   rD   r   meanr   r    r   r   rB   rE   rF   Z
zeros_liker;   r   sumrA   r@   )r,   ZscoreresultsZ	gt_labelsclassesZclZ
masked_iouZobservedrJ   Zgt_labZscoresr/   rG   r0   compute   s     
 zIntersectionOverUnion.compute)valaxr#   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 object and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> import torch
            >>> from torchmetrics.detection import IntersectionOverUnion
            >>> preds = [
            ...    {
            ...        "boxes": torch.tensor([[296.55, 93.96, 314.97, 152.79], [298.55, 98.96, 314.97, 151.79]]),
            ...        "scores": torch.tensor([0.236, 0.56]),
            ...        "labels": torch.tensor([4, 5]),
            ...    }
            ... ]
            >>> target = [
            ...    {
            ...        "boxes": torch.tensor([[300.00, 100.00, 315.00, 150.00]]),
            ...        "labels": torch.tensor([5]),
            ...    }
            ... ]
            >>> metric = IntersectionOverUnion()
            >>> metric.update(preds, target)
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.detection import IntersectionOverUnion
            >>> preds = [
            ...    {
            ...        "boxes": torch.tensor([[296.55, 93.96, 314.97, 152.79], [298.55, 98.96, 314.97, 151.79]]),
            ...        "scores": torch.tensor([0.236, 0.56]),
            ...        "labels": torch.tensor([4, 5]),
            ...    }
            ... ]
            >>> target = lambda : [
            ...    {
            ...        "boxes": torch.tensor([[300.00, 100.00, 315.00, 150.00]]) + torch.randint(-10, 10, (1, 4)),
            ...        "labels": torch.tensor([5]),
            ...    }
            ... ]
            >>> metric = IntersectionOverUnion()
            >>> vals = []
            >>> for _ in range(20):
            ...     vals.append(metric(preds, target()))
            >>> fig_, ax_ = metric.plot(vals)

        )Z_plot)r,   rR   rS   r/   r/   r0   plot   s    Ar   )r   NFT)NN)!__name__
__module____qualname____doc__r   r+   __annotations__r   r   r   r   r   r   strr   floatr   r&   staticmethodr4   r5   r   r@   r<   rH   dictrQ   r   r   r   r   rT   __classcell__r/   r/   r-   r0   r   %   sB   
`    "* )typingr   r   r   r   r   r   rC   r   Ztorchmetrics.detection.helpersr	   r
   Z%torchmetrics.functional.detection.iour   r   Ztorchmetrics.metricr   Ztorchmetrics.utilities.datar   Ztorchmetrics.utilities.importsr   r   Ztorchmetrics.utilities.plotr   r   Ztorchvision.opsr   Z__doctest_skip__r   r/   r/   r/   r0   <module>   s     
