o  i-;@sddlmZddlmZddlmZddlZddlZddl m Z m Z m Z m Z ddlmZddlmZGd d d eZ  ddddZdS)) annotations)Sequence)AnyN)do_metric_reductionget_edge_surface_distanceignore_backgroundprepare_spacing)MetricReduction)CumulativeIterationMetriccsHeZdZdZddejddfdfdd ZdddZ d d!ddZZ S)"SurfaceDiceMetrica Computes the Normalized Surface Dice (NSD) for each batch sample and class of predicted segmentations `y_pred` and corresponding reference segmentations `y` according to equation :eq:`nsd`. This implementation is based on https://arxiv.org/abs/2111.05408 and supports 2D and 3D images. Be aware that by default (`use_subvoxels=False`), the computation of boundaries is different from DeepMind's implementation https://github.com/deepmind/surface-distance. In this implementation, the length/area of a segmentation boundary is interpreted as the number of its edge pixels. In DeepMind's implementation, the length of a segmentation boundary depends on the local neighborhood (cf. https://arxiv.org/abs/1809.04430). This issue is discussed here: https://github.com/Project-MONAI/MONAI/issues/4103. The class- and batch sample-wise NSD values can be aggregated with the function `aggregate`. Example of the typical execution steps of this metric class follows :py:class:`monai.metrics.metric.Cumulative`. Args: class_thresholds: List of class-specific thresholds. The thresholds relate to the acceptable amount of deviation in the segmentation boundary in pixels. Each threshold needs to be a finite, non-negative number. include_background: Whether to include NSD computation on the first channel of the predicted output. Defaults to ``False``. distance_metric: The metric used to compute surface distances. One of [``"euclidean"``, ``"chessboard"``, ``"taxicab"``]. Defaults to ``"euclidean"``. reduction: define mode of reduction to the metrics, will only apply reduction on `not-nan` values, available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``, ``"mean_channel"``, ``"sum_channel"``}, default to ``"mean"``. if "none", will not do reduction. get_not_nans: whether to return the `not_nans` count. Defaults to ``False``. `not_nans` is the number of batch samples for which not all class-specific NSD values were nan values. If set to ``True``, the function `aggregate` will return both the aggregated NSD and the `not_nans` count. If set to ``False``, `aggregate` will only return the aggregated NSD. use_subvoxels: Whether to use subvoxel distances. Defaults to ``False``. F euclideanclass_thresholds list[float]include_backgroundbooldistance_metricstr reductionMetricReduction | str get_not_nans use_subvoxelsreturnNonecs2t||_||_||_||_||_||_dSN)super__init__rrrrrr)selfrrrrrr __class__\/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/metrics/surface_dice.pyr>s  zSurfaceDiceMetric.__init__y_pred torch.Tensorykwargsrc Ks$t|||j|j|j|d|jdS)a Args: y_pred: Predicted segmentation, typically segmentation model output. It must be a one-hot encoded, batch-first tensor [B,C,H,W] or [B,C,H,W,D]. y: Reference segmentation. It must be a one-hot encoded, batch-first tensor [B,C,H,W] or [B,C,H,W,D]. kwargs: additional parameters: ``spacing`` should be passed to correctly compute the metric. ``spacing``: spacing of pixel (or voxel). This parameter is relevant only if ``distance_metric`` is set to ``"euclidean"``. If a single number, isotropic spacing with that value is used for all images in the batch. If a sequence of numbers, the length of the sequence must be equal to the image dimensions. This spacing will be used for all images in the batch. If a sequence of sequences, the length of the outer sequence must be equal to the batch size. If inner sequence has length 1, isotropic spacing with that value is used for all images in the batch, else the inner sequence length must be equal to the image dimensions. If ``None``, spacing of unity is used for all images in batch. Defaults to ``None``. use_subvoxels: Whether to use subvoxel distances. Defaults to ``False``. Returns: Pytorch Tensor of shape [B,C], containing the NSD values :math:`\operatorname {NSD}_{b,c}` for each batch index :math:`b` and class :math:`c`. spacing)r"r$rrrr&r)compute_surface_dicerrrgetr)rr"r$r%r r r!_compute_tensorOsz!SurfaceDiceMetric._compute_tensorNMetricReduction | str | None0torch.Tensor | tuple[torch.Tensor, torch.Tensor]cCsB|}t|tjstdt||p|j\}}|jr||fS|S)a Aggregates the output of `_compute_tensor`. Args: reduction: define mode of reduction to the metrics, will only apply reduction on `not-nan` values, available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``, ``"mean_channel"``, ``"sum_channel"``}, default to `self.reduction`. if "none", will not do reduction. Returns: If `get_not_nans` is set to ``True``, this function returns the aggregated NSD and the `not_nans` count. If `get_not_nans` is set to ``False``, this function returns only the aggregated NSD. z-the data to aggregate must be PyTorch Tensor.) get_buffer isinstancetorchTensor ValueErrorrrr)rrdatafnot_nansr r r! aggregateqs  zSurfaceDiceMetric.aggregate)rrrrrrrrrrrrrr)r"r#r$r#r%rrr#r)rr*rr+) __name__ __module__ __qualname____doc__r MEANrr)r4 __classcell__r r rr!r s& #r Fr r"r#r$rrrrrrr&\int | float | np.ndarray | Sequence[int | float | np.ndarray | Sequence[int | float]] | Nonerrc CsL|s t||d\}}t|tjrt|tjstd|dvs&|dvr*td|j|jkr=td|jd|jd|jdd \}}|t|krYtd |d t|d tt |retd tt |dkrrtdtj ||f|j tjd} |jd } t||| d} t ||D]\} } t|| | f|| | f|| | |d| d\\}}\}}}|st|t|}t||| kt||| k}n>|\}}||||}}||}t|dkr|||| knd}t|dkr|||| knd}||}|dkrtt j| | | f<q||| | | f<q| S)a This function computes the (Normalized) Surface Dice (NSD) between the two tensors `y_pred` (referred to as :math:`\hat{Y}`) and `y` (referred to as :math:`Y`). This metric determines which fraction of a segmentation boundary is correctly predicted. A boundary element is considered correctly predicted if the closest distance to the reference boundary is smaller than or equal to the specified threshold related to the acceptable amount of deviation in pixels. The NSD is bounded between 0 and 1. This implementation supports multi-class tasks with an individual threshold :math:`\tau_c` for each class :math:`c`. The class-specific NSD for batch index :math:`b`, :math:`\operatorname {NSD}_{b,c}`, is computed using the function: .. math:: \operatorname {NSD}_{b,c} \left(Y_{b,c}, \hat{Y}_{b,c}\right) = \frac{\left|\mathcal{D}_{Y_{b,c}}^{'}\right| + \left| \mathcal{D}_{\hat{Y}_{b,c}}^{'} \right|}{\left|\mathcal{D}_{Y_{b,c}}\right| + \left|\mathcal{D}_{\hat{Y}_{b,c}}\right|} :label: nsd with :math:`\mathcal{D}_{Y_{b,c}}` and :math:`\mathcal{D}_{\hat{Y}_{b,c}}` being two sets of nearest-neighbor distances. :math:`\mathcal{D}_{Y_{b,c}}` is computed from the predicted segmentation boundary towards the reference segmentation boundary and vice-versa for :math:`\mathcal{D}_{\hat{Y}_{b,c}}`. :math:`\mathcal{D}_{Y_{b,c}}^{'}` and :math:`\mathcal{D}_{\hat{Y}_{b,c}}^{'}` refer to the subsets of distances that are smaller or equal to the acceptable distance :math:`\tau_c`: .. math:: \mathcal{D}_{Y_{b,c}}^{'} = \{ d \in \mathcal{D}_{Y_{b,c}} \, | \, d \leq \tau_c \}. In the case of a class neither being present in the predicted segmentation, nor in the reference segmentation, a nan value will be returned for this class. In the case of a class being present in only one of predicted segmentation or reference segmentation, the class NSD will be 0. This implementation is based on https://arxiv.org/abs/2111.05408 and supports 2D and 3D images. The computation of boundaries follows DeepMind's implementation https://github.com/deepmind/surface-distance when `use_subvoxels=True`; Otherwise the length of a segmentation boundary is interpreted as the number of its edge pixels. Args: y_pred: Predicted segmentation, typically segmentation model output. It must be a one-hot encoded, batch-first tensor [B,C,H,W] or [B,C,H,W,D]. y: Reference segmentation. It must be a one-hot encoded, batch-first tensor [B,C,H,W] or [B,C,H,W,D]. class_thresholds: List of class-specific thresholds. The thresholds relate to the acceptable amount of deviation in the segmentation boundary in pixels. Each threshold needs to be a finite, non-negative number. include_background: Whether to include the surface dice computation on the first channel of the predicted output. Defaults to ``False``. distance_metric: The metric used to compute surface distances. One of [``"euclidean"``, ``"chessboard"``, ``"taxicab"``]. Defaults to ``"euclidean"``. spacing: spacing of pixel (or voxel). This parameter is relevant only if ``distance_metric`` is set to ``"euclidean"``. If a single number, isotropic spacing with that value is used for all images in the batch. If a sequence of numbers, the length of the sequence must be equal to the image dimensions. This spacing will be used for all images in the batch. If a sequence of sequences, the length of the outer sequence must be equal to the batch size. If inner sequence has length 1, isotropic spacing with that value is used for all images in the batch, else the inner sequence length must be equal to the image dimensions. If ``None``, spacing of unity is used for all images in batch. Defaults to ``None``. use_subvoxels: Whether to use subvoxel distances. Defaults to ``False``. Raises: ValueError: If `y_pred` and/or `y` are not PyTorch tensors. ValueError: If `y_pred` and/or `y` do not have four dimensions. ValueError: If `y_pred` and/or `y` have different shapes. ValueError: If `y_pred` and/or `y` are not one-hot encoded ValueError: If the number of channels of `y_pred` and/or `y` is different from the number of class thresholds. ValueError: If any class threshold is not finite. ValueError: If any class threshold is negative. Returns: Pytorch Tensor of shape [B,C], containing the NSD values :math:`\operatorname {NSD}_{b,c}` for each batch index :math:`b` and class :math:`c`. )r"r$z$y_pred and y must be PyTorch Tensor.)zAy_pred and y should be one-hot encoded: [B,C,H,W] or [B,C,H,W,D].z=y_pred and y should have same shape, but instead, shapes are z (y_pred) and z (y).Nznumber of classes (z-) does not match number of class thresholds (z).z'All class thresholds need to be finite.rz%All class thresholds need to be >= 0.)devicedtype)r& batch_sizeimg_dimT)rr&r symmetric class_indexg)rr-r.r/r0 ndimensionshapelenanynpisfinitearrayemptyr?floatndimrndindexrsumtensornan)r"r$rrrr&rrAn_classZnsdrB spacing_listbc edges_prededges_gtZdistances_pred_gtZdistances_gt_predareasZboundary_completeZboundary_correct areas_predareas_gtZgt_trueZ pred_truer r r!r's^P       $& r')Fr NF)r"r#r$r#rrrrrrr&r;rrrr#) __future__rcollections.abcrtypingrnumpyrIr.monai.metrics.utilsrrrr monai.utilsr metricr r r'r r r r!s    s