o
    .wi3                     @   s   d dl mZ d dl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sOddgZnesTdgZG dd deZdS )    )Sequence)AnyListOptionalUnionN)Tensor)_fix_empty_tensors_input_validator)_iou_compute_iou_update)Metric)dim_zero_cat)_MATPLOTLIB_AVAILABLE_TORCHVISION_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEIntersectionOverUnionIntersectionOverUnion.plotc                       sl  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< e
e ed	< d
Zeed< dZeed< 				d,dedee dedededdf fddZedededefddZedededefddZdeeeef  deeeef  ddfdd Zd!edefd"d#Zdefd$d%Zdefd&d'Z	d-d(eeeee f  d)ee def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pred_labels
iou_matrixiou	_iou_typeg      _invalid_valxyxyN
box_formatiou_thresholdclass_metricsrespect_labelskwargsreturnc                    s   t  jdi | tstd| j  dd}||vr&td| d| || _|| _t	|t
s5td|| _t	|t
sAtd|| _| jdg d d	 | jd
g d d	 | jdg d d	 d S )NzMetric `zf` requires that `torchvision` is installed. Please install with `pip install torchmetrics[detection]`.)r   xywh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   )defaultdist_reduce_fxr   r    )super__init__r   ModuleNotFoundErrorr   upper
ValueErrorr   r   
isinstanceboolr    r!   	add_state)selfr   r   r    r!   r"   allowed_box_formats	__class__r(   W/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/detection/iou.pyr*      s&   

zIntersectionOverUnion.__init__argsc                  O      t | i |S N)r   r6   r"   r(   r(   r5   _iou_update_fn      z$IntersectionOverUnion._iou_update_fnc                  O   r7   r8   )r
   r9   r(   r(   r5   _iou_compute_fn   r;   z%IntersectionOverUnion._iou_compute_fnpredstargetc           	      C   s   t ||dd t||D ]b\}}| |d }| |d }| j|d  | j|d  | ||| j| j}| j	rh|
 dkrV|
 dkrV|d d|d dk}ntj|jd t|jd}| j|| < | j| qdS )	z*Update state with predictions and targets.T)ignore_scoreboxeslabelsr      )dtypedeviceN)r	   zip_get_safe_item_valuesr   appendr   r:   r   r   r!   numel	unsqueezetorcheyeshaper/   rD   r   )	r1   r=   r>   p_it_i	det_boxesgt_boxesr   label_eqr(   r(   r5   update   s   zIntersectionOverUnion.updater@   c                 C   s4   ddl m} t|}| dkr||| jdd}|S )Nr   )box_convertr   )in_fmtout_fmt)torchvision.opsrS   r   rH   r   )r1   r@   rS   r(   r(   r5   rF      s
   z+IntersectionOverUnion._get_safe_item_valuesc                 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   rJ   catuniquetolistr1   r(   r(   r5   _get_gt_classes   s   z%IntersectionOverUnion._get_gt_classesc                    sf   fdd j D }|rt|d ntjd jd} j |i}t|r3tjd|jd| j <  jrt	t	 j
t	 jg}| dkrN|  ng }|D ]^}t|}t|}t j  j
D ]!\}	}
|	dd|
|kf }|| jk }|| 7 }|| 7 }qe| dkr| j d| tjd|jdi qR| j d| || i qR|S )z@Computes IoU based on inputs passed in to ``update`` previously.c                    s*   g | ]}t | jkr|| jk qS r(   )rJ   anyr   ).0matr[   r(   r5   
<listcomp>   s
    z1IntersectionOverUnion.compute.<locals>.<listcomp>r   g        )rD   Nz/cl_)r   rJ   rX   meantensorrD   r   isnanr    r   r   r   rH   rY   rZ   
zeros_likerE   r   sumitemrR   )r1   valid_matricesscoreresults
all_labelsclassescl
masked_iouobservedr_   gt_labscoresvalid_scoresr(   r[   r5   compute   s,   
$


( zIntersectionOverUnion.computevalaxc                 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)

        )_plot)r1   rs   rt   r(   r(   r5   plot   s   Ar   )r   NFT)NN)!__name__
__module____qualname____doc__r   r/   __annotations__r   r   r   r   r   r   strr   floatr   r*   staticmethodr:   r<   listdictrR   rF   r\   rr   r   r   r   r   rv   __classcell__r(   r(   r3   r5   r   !   sV   
 a#.)collections.abcr   typingr   r   r   r   rJ   r   torchmetrics.detection.helpersr   r	   %torchmetrics.functional.detection.iour
   r   torchmetrics.metricr   torchmetrics.utilities.datar   torchmetrics.utilities.importsr   r   torchmetrics.utilities.plotr   r   __doctest_skip__r   r(   r(   r(   r5   <module>   s   
