o
    i)                     @  s|   d dl mZ d dlZd dlmZ d dlZd dlmZ d dlm	Z	 d dl
mZ d dlmZ G dd	 d	eZG d
d deZdS )    )annotationsN)Callable)_Loss)one_hot)distance_transform_edt)LossReductionc                      sR   e Zd ZdZddddddejdfd fddZe dddZ	dddZ
  ZS ) HausdorffDTLossa  
    Compute channel-wise binary Hausdorff loss based on distance transform. It can support both multi-classes and
    multi-labels tasks. The data `input` (BNHW[D] where N is number of classes) is compared with ground truth `target`
    (BNHW[D]).

    Note that axis N of `input` is expected to be logits or probabilities for each class, if passing logits as input,
    must set `sigmoid=True` or `softmax=True`, or specifying `other_act`. And the same axis of `target`
    can be 1 or N (one-hot format).

    The original paper: Karimi, D. et. al. (2019) Reducing the Hausdorff Distance in Medical Image Segmentation with
    Convolutional Neural Networks, IEEE Transactions on medical imaging, 39(2), 499-513
    g       @FNalphafloatinclude_backgroundboolto_onehot_ysigmoidsoftmax	other_actCallable | None	reductionLossReduction | strbatchreturnNonec	           	        s   t  jt|jd |durt|stdt|j dt|t| dkr+t	d|| _
|| _|| _|| _|| _|| _|| _dS )a  
        Args:
            include_background: if False, channel index 0 (background category) is excluded from the calculation.
                if the non-background segmentations are small compared to the total image size they can get overwhelmed
                by the signal from the background so excluding it in such cases helps convergence.
            to_onehot_y: whether to convert the ``target`` into the one-hot format,
                using the number of classes inferred from `input` (``input.shape[1]``). Defaults to False.
            sigmoid: if True, apply a sigmoid function to the prediction.
            softmax: if True, apply a softmax function to the prediction.
            other_act: callable function to execute other activation layers, Defaults to ``None``. for example:
                ``other_act = torch.tanh``.
            reduction: {``"none"``, ``"mean"``, ``"sum"``}
                Specifies the reduction to apply to the output. Defaults to ``"mean"``.

                - ``"none"``: no reduction will be applied.
                - ``"mean"``: the sum of the output will be divided by the number of elements in the output.
                - ``"sum"``: the output will be summed.
            batch: whether to sum the intersection and union areas over the batch dimension before the dividing.
                Defaults to False, a loss value is computed independently from each item in the batch
                before any `reduction`.

        Raises:
            TypeError: When ``other_act`` is not an ``Optional[Callable]``.
            ValueError: When more than 1 of [``sigmoid=True``, ``softmax=True``, ``other_act is not None``].
                Incompatible values.

        )r   Nz*other_act must be None or callable but is .   zXIncompatible values: more than 1 of [sigmoid=True, softmax=True, other_act is not None].)super__init__r   valuecallable	TypeErrortype__name__int
ValueErrorr	   r   r   r   r   r   r   )	selfr	   r   r   r   r   r   r   r   	__class__ ]/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/losses/hausdorff_loss.pyr   ,   s   &
zHausdorffDTLoss.__init__imgtorch.Tensorc                 C  s^   t |}tt|D ]!}|| dk}| r,| s,t|}| }t|}|| ||< q|S )zGenerate distance transform.

        Args:
            img (np.ndarray): input mask as NCHWD or NCHW.

        Returns:
            np.ndarray: Distance field.
        g      ?)torch
zeros_likerangelenanyallr   )r"   r'   field	batch_idxZfg_maskZfg_distZbg_maskZbg_distr%   r%   r&   distance_field`   s   

zHausdorffDTLoss.distance_fieldinputtargetc                 C  sn  |  dkr|  dkrtd| jrt|}|jd }| jr0|dkr*td nt|d}| jdur:| |}| j	rM|dkrGtd nt
||d}| jsn|dkrZtd	 n|ddddf }|ddddf }|j|jkrtd
|j d|j d|j}g }t|jd D ]Z}|dd|gf }|dd|gf }| |  }	| |  }
|| d }|	| j |
| j  }||| }tdt|j }| jrdg| }||j|dd qtj|dd}| jtjjkrt|}|S | jtjjkrt |}|S | jtj!jkr.t"|jdd dgt|jd   }|#|}|S td| j d)aK  
        Args:
            input: the shape should be BNHW[D], where N is the number of classes.
            target: the shape should be BNHW[D] or B1HW[D], where N is the number of classes.

        Raises:
            ValueError: If the input is not 2D (NCHW) or 3D (NCHWD).
            AssertionError: When input and target (after one hot transform if set)
                have different shapes.
            ValueError: When ``self.reduction`` is not one of ["mean", "sum", "none"].

        Example:
            >>> import torch
            >>> from monai.losses.hausdorff_loss import HausdorffDTLoss
            >>> from monai.networks.utils import one_hot
            >>> B, C, H, W = 7, 5, 3, 2
            >>> input = torch.rand(B, C, H, W)
            >>> target_idx = torch.randint(low=0, high=C - 1, size=(B, H, W)).long()
            >>> target = one_hot(target_idx[:, None, ...], num_classes=C)
            >>> self = HausdorffDTLoss(reduction='none')
            >>> loss = self(input, target)
            >>> assert np.broadcast_shapes(loss.shape, input.shape) == input.shape
              z'Only 2D (NCHW) and 3D (NCHWD) supportedr   z2single channel prediction, `softmax=True` ignored.Nz6single channel prediction, `to_onehot_y=True` ignored.)num_classesz>single channel prediction, `include_background=False` ignored.z"ground truth has different shape (z) from input ()   r   T)dimkeepdim)r9   zUnsupported reduction: z0, available options are ["mean", "sum", "none"].)$r9   r!   r   r)   shaper   warningswarnr   r   r   r   AssertionErrordevicer+   r1   detachr
   r	   toaranger,   tolistr   appendmeancatr   r   MEANr   SUMsumNONElistview)r"   r2   r3   	n_pred_chr?   Zall_fiZch_inputZ	ch_targetZpred_dtZ	target_dtZ
pred_errordistanceZ	running_freduce_axisfbroadcast_shaper%   r%   r&   forward{   s`   






	&
zHausdorffDTLoss.forward)r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r'   r(   r   r(   r2   r(   r3   r(   r   r(   )r   
__module____qualname____doc__r   rG   r   r)   no_gradr1   rS   __classcell__r%   r%   r#   r&   r      s    4r   c                      s"   e Zd ZdZd fddZ  ZS )	LogHausdorffDTLossa  
    Compute the logarithm of the Hausdorff Distance Transform Loss.

    This class computes the logarithm of the Hausdorff Distance Transform Loss, which is based on the distance transform.
    The logarithm is computed to potentially stabilize and scale the loss values, especially when the original loss
    values are very small.

    The formula for the loss is given by:
        log_loss = log(HausdorffDTLoss + 1)

    Inherits from the HausdorffDTLoss class to utilize its distance transform computation.
    r2   r(   r3   r   c                   s   t t ||d }|S )a  
        Compute the logarithm of the Hausdorff Distance Transform Loss.

        Args:
            input (torch.Tensor): The shape should be BNHW[D], where N is the number of classes.
            target (torch.Tensor): The shape should be BNHW[D] or B1HW[D], where N is the number of classes.

        Returns:
            torch.Tensor: The computed Log Hausdorff Distance Transform Loss for the given input and target.

        Raises:
            Any exceptions raised by the parent class HausdorffDTLoss.
        r   )r)   logr   rS   )r"   r2   r3   Zlog_lossr#   r%   r&   rS      s   zLogHausdorffDTLoss.forwardrT   )r   rU   rV   rW   rS   rY   r%   r%   r#   r&   rZ      s    rZ   )
__future__r   r<   typingr   r)   torch.nn.modules.lossr   monai.networksr   monai.transforms.utilsr   monai.utilsr   r   rZ   r%   r%   r%   r&   <module>   s    8