o
    oi(                     @  s   d dl mZ d dlmZ d dlZd dlmZ d dlmZmZm	Z	m
Z
mZmZmZ G dd deZG dd	 d	eZG d
d deZdS )    )annotations)CallableN)nn)ModuleTensor	as_tensorstacktensorwhere
zeros_likec                      sT   e Zd ZU dZded< ded< dd fddZdddZdddZdddZ  Z	S )_HausdorffERLossBasea#  Base class for binary Hausdorff loss based on morphological erosion.

    This is an Hausdorff Distance (HD) Loss that based on morphological erosion,which provided
    a differentiable approximation of Hausdorff distance as stated in :cite:`karimi2019reducing`.
    The code is refactored on top of `here <https://github.com/PatRyg99/HausdorffLoss/
        blob/master/hausdorff_loss.py>`__.

    Args:
        alpha: controls the erosion rate in each iteration.
        k: the number of iterations of erosion.
        reduction: Specifies the reduction to apply to the output: 'none' | 'mean' | 'sum'.
            'none': no reduction will be applied, 'mean': the weighted mean of the output is taken,
            'sum': the output will be summed.

    Returns:
        Estimated Hausdorff Loss.

    zCallable[..., Tensor]convmax_pool       @
   meanalphafloatkint	reductionstrreturnNonec                   s0   t    || _|| _|| _| d|   d S )Nkernel)super__init__r   r   r   register_buffer
get_kernel)selfr   r   r   	__class__ K/home/ubuntu/.local/lib/python3.10/site-packages/kornia/losses/hausdorff.pyr   3   s
   
z_HausdorffERLossBase.__init__r   c                 C  s   t ),Get kernel for image morphology convolution.)NotImplementedError)r   r"   r"   r#   r   :   s   z_HausdorffERLossBase.get_kernelpredtargetc                 C  s   || d }t | j|j|jd}t||j|jd}tj||jtjd}|dd d }t	| j
D ]L}| j|||dd}	|	d }
d|
|
dk < | |
}| |
  }|| dk}| }| rp|
| ||  }t|| ||
}
||
|d | j   }|
}q1|S )N   devicedtype   )weightpaddinggroupsg      ?r   )r   r   r*   r+   r   torch	ones_likeboolsizeranger   r   r   squeezeanyr
   r   )r   r&   r'   boundr   erodedmaskr/   r   dilationerosionerosion_maxerosion_min_to_normto_norm_erosion_to_fillr"   r"   r#   perform_erosion>   s&   
z$_HausdorffERLossBase.perform_erosionc                   s    j dd j dd kr ddkrddks,td j  dj  d d  k r;tdt fd	d
t dD }jdkrX| }|S jdkrc|	 }|S jdkrk	 |S t
dj d)ao  Compute Hausdorff loss.

        Args:
            pred: predicted tensor with a shape of :math:`(B, C, H, W)` or :math:`(B, C, D, H, W)`.
                Each channel is as binary as: 1 -> fg, 0 -> bg.
            target: target tensor with a shape of :math:`(B, 1, H, W)` or :math:`(B, C, D, H, W)`.

        Returns:
            Estimated Hausdorff Loss.

        r(   Nr   r-   zTPrediction and target need to be of same size, and target should not be one-hot.Got z and .zInvalid target value.c                   sT   g | ]&}  d d ||d f t|ktdjjdtdjjdqS )Nr-   r)   r   )rB   r
   r	   r*   r+   ).0ir&   r   r'   r"   r#   
<listcomp>w   s    	z0_HausdorffERLossBase.forward.<locals>.<listcomp>r   sumnonezreduction `z` has not been implemented yet.)shaper4   
ValueErrormaxitemr   r5   r   r   rH   r%   )r   r&   r'   outr"   rF   r#   forwarda   s2   >	


z_HausdorffERLossBase.forward)r   r   r   )r   r   r   r   r   r   r   r   r   r   r&   r   r'   r   r   r   )
__name__
__module____qualname____doc____annotations__r   r   rB   rO   __classcell__r"   r"   r    r#   r      s   
 

#r   c                      <   e Zd ZdZejZedZ	dddZ
d fd	d
Z  ZS )HausdorffERLossa>  Binary Hausdorff loss based on morphological erosion.

    Hausdorff Distance loss measures the maximum distance of a predicted segmentation boundary to
    the nearest ground-truth edge pixel. For two segmentation point sets X and Y ,
    the one-sided HD from X to Y is defined as:

    .. math::

        hd(X,Y) = \max_{x \in X} \min_{y \in Y}||x - y||_2

    Furthermore, the bidirectional HD is:

    .. math::

        HD(X,Y) = max(hd(X, Y), hd(Y, X))

    This is an Hausdorff Distance (HD) Loss that based on morphological erosion, which provided
    a differentiable approximation of Hausdorff distance as stated in :cite:`karimi2019reducing`.
    The code is refactored on top of `here <https://github.com/PatRyg99/HausdorffLoss/
    blob/master/hausdorff_loss.py>`__.

    Args:
        alpha: controls the erosion rate in each iteration.
        k: the number of iterations of erosion.
        reduction: Specifies the reduction to apply to the output: 'none' | 'mean' | 'sum'.
            'none': no reduction will be applied, 'mean': the weighted mean of the output is taken,
            'sum': the output will be summed.

    Examples:
        >>> hdloss = HausdorffERLoss()
        >>> input = torch.randn(5, 3, 20, 20)
        >>> target = (torch.rand(5, 1, 20, 20) * 2).long()
        >>> res = hdloss(input, target)

    r-   r   r   c                 C  s,   t g dg dg dgg}|d }|d S )r$   r   r-   r   r-   r-   r-   g?N)r	   )r   crossr   r"   r"   r#   r      s   zHausdorffERLoss.get_kernelr&   r'   c                   s   |  dkrtd|   d| |dk r%| dkr%|jtjks:td|d d|  d|  d	t 	||S )
a9  Compute Hausdorff loss.

        Args:
            pred: predicted tensor with a shape of :math:`(B, C, H, W)`.
                Each channel is as binary as: 1 -> fg, 0 -> bg.
            target: target tensor with a shape of :math:`(B, 1, H, W)`.

        Returns:
            Estimated Hausdorff Loss.

           zOnly 2D images supported. Got rC   r-   r   z+Expect long type target value in range (0, z). (z, ))
dimrK   rL   r4   minr+   r1   longr   rO   r   r&   r'   r    r"   r#   rO      s   *$zHausdorffERLoss.forwardrP   rQ   )rR   rS   rT   rU   r1   conv2dr   r   AdaptiveMaxPool2dr   r   rO   rW   r"   r"   r    r#   rY      s    $

rY   c                      rX   )HausdorffERLoss3DaM  Binary 3D Hausdorff loss based on morphological erosion.

    Hausdorff Distance loss measures the maximum distance of a predicted segmentation boundary to
    the nearest ground-truth edge pixel. For two segmentation point sets X and Y ,
    the one-sided HD from X to Y is defined as:

    .. math::

        hd(X,Y) = \max_{x \in X} \min_{y \in Y}||x - y||_2

    Furthermore, the bidirectional HD is:

    .. math::

        HD(X,Y) = max(hd(X, Y), hd(Y, X))

    This is a 3D Hausdorff Distance (HD) Loss that based on morphological erosion, which provided
    a differentiable approximation of Hausdorff distance as stated in :cite:`karimi2019reducing`.
    The code is refactored on top of `here <https://github.com/PatRyg99/HausdorffLoss/
    blob/master/hausdorff_loss.py>`__.

    Args:
        alpha: controls the erosion rate in each iteration.
        k: the number of iterations of erosion.
        reduction: Specifies the reduction to apply to the output: 'none' | 'mean' | 'sum'.
            'none': no reduction will be applied, 'mean': the weighted mean of the output is taken,
            'sum': the output will be summed.

    Examples:
        >>> hdloss = HausdorffERLoss3D()
        >>> input = torch.randn(5, 3, 20, 20, 20)
        >>> target = (torch.rand(5, 1, 20, 20, 20) * 2).long()
        >>> res = hdloss(input, target)

    r-   r   r   c                 C  sT   t g dg dg dgg}t g dg dg dgg}t|||gdd }|d S )r$   rZ   r[   )r   r   r   r-   g$I$I?N)r	   r   )r   r\   r8   r   r"   r"   r#   r      s   zHausdorffERLoss3D.get_kernelr&   r'   c                   s.   |  dkrtd|   dt ||S )aB  Compute 3D Hausdorff loss.

        Args:
            pred: predicted tensor with a shape of :math:`(B, C, D, H, W)`.
                Each channel is as binary as: 1 -> fg, 0 -> bg.
            target: target tensor with a shape of :math:`(B, 1, D, H, W)`.

        Returns:
            Estimated Hausdorff Loss.

           zOnly 3D images supported. Got rC   )r_   rK   r   rO   rb   r    r"   r#   rO     s   zHausdorffERLoss3D.forwardrP   rQ   )rR   rS   rT   rU   r1   conv3dr   r   AdaptiveMaxPool3dr   r   rO   rW   r"   r"   r    r#   re      s    $


re   )
__future__r   typingr   r1   r   kornia.corer   r   r   r   r	   r
   r   r   rY   re   r"   r"   r"   r#   <module>   s   $tD