U Phc @s0ddlmZddlZddlmZmZddlmZddlm Z m Z m Z ddl Z ddlZddlmZmZddlmZddlmZdd lmZmZmZmZmZmZmZmZm Z m!Z!e!d d d \Z"Z#e!d d d \ZZ#e!d dd \Z$Z#ddddddddgZ%ddddddZ&ej'fddddddZ(ed d!d"d#d$d%ed d"d&d'd(dSd*d*d+d,d-d,dd.d/dZ)dTd*d*d1d2d*d3d4dZ*dUddd1d2d,d,d+d6d7d8d9Z+dd1d:d;ddZ-d?d+d+d@dAdBdZ.dCdDgdEd)ggdFdGgdHdIggdCdDgdEd)gggdJZ/eddKdWdLdMZ0dXdNdOZ1dYdPdQZ2dZdRdZ3dS)[) annotationsN) lru_cachepartial) ModuleType)AnyIterableSequence)NdarrayOrTensor NdarrayTensor)CropForegroundD)distance_transform_edt) MetricReductionconvert_to_cupyconvert_to_dst_typeconvert_to_numpyconvert_to_tensordeprecated_argdeprecated_arg_defaultensure_tuple_replook_up_optionoptional_importzscipy.ndimage.morphologybinary_erosionnamer distance_transform_cdtignore_backgrounddo_metric_reductionget_mask_edgesget_surface_distanceis_binary_tensorremap_instance_idprepare_spacingget_code_to_measure_tabler z#tuple[NdarrayTensor, NdarrayTensor])y_predyreturncCsT|jddkr"|ddddfn|}|jddkrH|ddddfn|}||fS)al This function is used to remove background (the first channel) for `y_pred` and `y`. Args: y_pred: predictions. As for classification tasks, `y_pred` should has the shape [BN] where N is larger than 1. As for segmentation tasks, the shape should be [BNHW] or [BNHWD]. y: ground truth, the first dim is batch. N)shape)r#r$r(H/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/metrics/utils.pyr6s &&z torch.TensorzMetricReduction | strz'tuple[torch.Tensor | Any, torch.Tensor])f reductionr%cCst|}|}tjd|jtjd}t|t}|tjkrD||fSd||<|tjkr|j dd}t |dk|j dd||}|dkj dd}t |dk|j dd||}n*|tj kr|j ddgd}tj |ddgd}n|tj kr4|j dd}t |dk|j dd||}n|tj krb|j dd}|j dd}n|tjkr|j dd}t |dk|j dd||}nJ|tjkr|j dd}|j dd}n|tjkrtd|d||fS)ak This function is to do the metric reduction for calculated `not-nan` metrics of each sample's each class. The function also returns `not_nans`, which counts the number of not nans for the metric. Args: f: a tensor that contains the calculated metric scores per batch and per class. The first two dims should be batch and class. reduction: define the mode to reduce 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", return the input f tensor and not_nans. Raises: ValueError: When ``reduction`` is not one of ["mean", "sum", "mean_batch", "sum_batch", "mean_channel", "sum_channel" "none"]. r&devicedtyperdimzUnsupported reduction: zi, available options are ["mean", "sum", "mean_batch", "sum_batch", "mean_channel", "sum_channel" "none"].)torchisnanzerosr-floatrr NONEMEANsumwhereSUM MEAN_BATCH SUM_BATCH MEAN_CHANNEL SUM_CHANNEL ValueError)r*r+nansnot_nansZt_zeror(r(r)rGs@     "&  $  $   always_return_as_numpyz1.3.0z1.5.0TF)rsincereplaced old_default new_defaultz1.7.0zQThe option is removed and the return type will always be equal to the input type.)rrBremoved msg_suffixr&r intboolzSequence | None)seg_predseg_gt label_idxcropspacingrAr%cCstddd\}}|j|jkr6td|jd|jdt|tjrZ|sZtt|jd}t} nt }t } |dko|ot|tjo|jj d k} |j t tj fkr||k}|j t tj fkr||k}|r||B} | s| j|jt d | j|jt d } } |dkr| | fS| | | | fS|d|d| dg}|dkrJ| sJt|d t d \}}} nt|tjd \}}} td dgdddddd}|||| d}|d d|dd}}|dkr| st ||gt d \}}t||A}t||A}n,t||gt d \}}|||A}|||A}|||ft d St||jd\}}t|}|dkrHtjjjntjjj}tj|d|dgdd}||||\}}t|d}|dk||k@}|dk||k@}t|d|d |j}t|d|d |j}|d|d|d|df}||ddS)a Compute edges from binary segmentation masks. This function is helpful to further calculate metrics such as Average Surface Distance and Hausdorff Distance. The input images can be binary or labelfield images. If labelfield images are supplied, they are converted to binary images using `label_idx`. In order to improve the computing efficiency, before getting the edges, the images can be cropped and only keep the foreground if not specifies ``crop = False``. We require that images are the same size, and assume that they occupy the same space (spacing, orientation, etc.). Args: seg_pred: the predicted binary or labelfield image. seg_gt: the actual binary or labelfield image. label_idx: for labelfield images, convert to binary with `seg_pred = seg_pred == label_idx`. crop: crop input images and only keep the foregrounds. In order to maintain two inputs' shapes, here the bounding box is achieved by ``(seg_pred | seg_gt)`` which represents the union set of two images. Defaults to ``True``. spacing: the input spacing. If not None, the subvoxel edges and areas will be computed. otherwise `scipy`'s binary erosion is used to calculate the edges. always_return_as_numpy: whether to a numpy array regardless of the input type. If False, return the same type as inputs. zcucim.skimage.morphologyrrz1seg_pred and seg_gt should have same shapes, got z and .r-Ncudar.cpur,predgtsrcr&F) source_keymargin allow_smallerstart_coord_key end_coord_key)rTrUrVrr/) wrap_sequence)!rr'r> isinstancer1Tensorrrr-rnptyper.rIanyr3float16r rrr"lennn functionalconv3dconv2dstackr4to index_selectviewrHreshape)rJrKrLrMrNrAZcucim_binary_erosionZhas_cucim_binary_erosion converterlibZ use_cucimZor_volrTrU channel_firstcroppercropped edges_prededges_gtZcode_to_area_tablek spatial_dimsconvvolZ code_predZcode_gtall_onesZ areas_predZareas_gtretr(r(r)rsv.    "        euclideanstrz7int | float | np.ndarray | Sequence[int | float] | None)rJrKdistance_metricrNr%cCst|tjrtnt}|s4tj|j||jd}n||sptj|j||jd}||}t|||j ddS|dkrt |d|dd}n,|dkrt t ||d}nt d|d t|||jdd}||S) ae This function is used to compute the surface distances from `seg_pred` to `seg_gt`. Args: seg_pred: the edge of the predictions. seg_gt: the edge of the ground truth. distance_metric: : [``"euclidean"``, ``"chessboard"``, ``"taxicab"``] the metric used to compute surface distance. Defaults to ``"euclidean"``. - ``"euclidean"``, uses Exact Euclidean distance transform. - ``"chessboard"``, uses `chessboard` metric in chamfer type of transform. - ``"taxicab"``, uses `taxicab` metric in chamfer type of transform. spacing: spacing of pixel (or voxel). This parameter is relevant only if ``distance_metric`` is set to ``"euclidean"``. Several input options are allowed: (1) If a single number, isotropic spacing with that value is used. (2) If a sequence of numbers, the length of the sequence must be equal to the image dimensions. (3) If ``None``, spacing of unity is used. Defaults to ``None``. Note: If seg_pred or seg_gt is all 0, may result in nan/inf distance. rRrr|)N.)sampling>taxicab chessboard)metriczdistance_metric z is not implemented.)r_r1r`rarcinf ones_likefloat32rr.monai_distance_transform_edtrrr>)rJrKr~rNrpdisr(r(r)rs r]ztuple[tuple[torch.Tensor, torch.Tensor], tuple[torch.Tensor, torch.Tensor] | tuple[torch.Tensor], tuple[torch.Tensor, torch.Tensor] | tuple[()]])r#r$r~rN use_subvoxels symmetric class_indexr%c Csd}|r$|dk r|ndgt|j}t||d|dd^}} } | sbtd|dkrV|ndd |std |dkr||ndd |rt|| ||t| |||f} nt|| ||f} t|| f| t| f|j d S) af This function is used to compute the surface distance from `y_pred` to `y` using the edges of the masks. Args: y_pred: the predicted binary or labelfield image. Expected to be in format (H, W[, D]). y: the actual binary or labelfield image. Expected to be in format (H, W[, D]). distance_metric: : [``"euclidean"``, ``"chessboard"``, ``"taxicab"``] See :py:func:`monai.metrics.utils.get_surface_distance`. spacing: spacing of pixel (or voxel). This parameter is relevant only if ``distance_metric`` is set to ``"euclidean"``. See :py:func:`monai.metrics.utils.get_surface_distance`. use_subvoxels: whether to use subvoxel resolution (using the spacing). This will return the areas of the edges. symmetric: whether to compute the surface distance from `y_pred` to `y` and from `y` to `y_pred`. class_index: The class-index used for context when warning about empty ground truth or prediction. Returns: (edges_pred, edges_gt), (distances_pred_to_gt, [distances_gt_to_pred]), (areas_pred, areas_gt) | tuple() Nr&TF)rMrNrAzthe ground truth of class r]Unknownz/ is all 0, this may result in nan/inf distance.zthe prediction of class rP) rer'rrcwarningswarnrrtupler-) r#r$r~rNrrrZ edges_spacingrtruareas distancesr(r(r)get_edge_surface_distance"s0    rNone)inputrr%cCsXt|tjst|dt||krD|dksD|dkrTt |ddS)aMDetermines whether the input tensor is torch binary tensor or not. Args: input (torch.Tensor): tensor to validate. name (str): name of the tensor being checked. Raises: ValueError: if `input` is not a PyTorch Tensor. Note: A warning message is printed, if the tensor is not binary. z must be of type PyTorch Tensor.r&rz should be a binarized tensor.N) r_r1r`r>allbytemaxminrr)rrr(r(r)r]s *)rTby_sizer%c st}dd|D}|s"S|r`fdd|D}t||}t|dddd}t|\}}tjtjd}t|D]\}} |d || k<qx|S) ae This function is used to rename all instance id of `pred`, so that the id is contiguous. For example: all ids of the input can be [0, 1, 2] rather than [0, 2, 5]. This function is helpful for calculating metrics like Panoptic Quality (PQ). The implementation refers to: https://github.com/vqdang/hover_net Args: pred: segmentation predictions in the form of torch tensor. Each value of the tensor should be an integer, and represents the prediction of its corresponding instance id. by_size: if True, largest instance will be assigned a smaller id. cSsg|]}|dkr|qS)rr().0ir(r(r) sz%remap_instance_id..csg|]}|kqSr()r7)r instance_idrTr(r)rscSs|dS)Nr&r()xr(r(r)z#remap_instance_id..T)keyreverserRr&)listuniquezipsortedr1 zeros_likerH enumerate) rTrZpred_idZ instance_sizeZ pair_dataZ pair_list_Znew_predidxrr(rr)r ps   z\int | float | np.ndarray | Sequence[int | float | np.ndarray | Sequence[int | float]] | NonezASequence[None | int | float | np.ndarray | Sequence[int | float]])rN batch_sizeimg_dimr%csldkstttfr$tg|StttjfrXtfddtDr`tddtdttjfrt |krtd|ddtfd dtDrtd ddt d dtDstd dtStdttfrBt kr,td ddfddt |DStdt dtdddS)a This function is used to prepare the `spacing` parameter to include batch dimension for the computation of surface distance, hausdorff distance or surface dice. An example with batch_size = 4 and img_dim = 3: input spacing = None -> output spacing = [None, None, None, None] input spacing = 0.8 -> output spacing = [0.8, 0.8, 0.8, 0.8] input spacing = [0.8, 0.5, 0.9] -> output spacing = [[0.8, 0.5, 0.9], [0.8, 0.5, 0.9], [0.8, 0.5, 0.9], [0.8, 0.5, 0.9]] input spacing = [0.8, 0.7, 1.2, 0.8] -> output spacing = [0.8, 0.7, 1.2, 0.8] (same as input) An example with batch_size = 3 and img_dim = 3: input spacing = [0.8, 0.5, 0.9] -> output spacing = [[0.8, 0.5, 0.9], [0.8, 0.5, 0.9], [0.8, 0.5, 0.9], [0.8, 0.5, 0.9]] Args: spacing: can be a float, a sequence of length `img_dim`, or a sequence with length `batch_size` that includes floats or sequences of length `img_dim`. Raises: ValueError: when `spacing` is a sequence of sequence, where the outer sequence length does not equal `batch_size` or inner sequence length does not equal `img_dim`. Returns: spacing: a sequence with length `batch_size` that includes integers, floats or sequences of length `img_dim`. Nc3s"|]}t|td VqdS)rN)r_rbrsrNr(r) sz"prepare_spacing..zEif `spacing` is a sequence, its elements should be of same type, got rOrzcif `spacing` is a sequence of sequences, the outer sequence should have same length as batch size (z), got c3s|]}t|kVqdSN)rer)rr(r)rszKeach element of `spacing` list should either have same length asimage dim (css*|]"}t|D]}t|ttfVqqdSr)rr_rHr4)rrrr(r(r)rs ziif `spacing` is a sequence of sequences or 2D np.ndarray, the elements should be integers or floats, got zPif `spacing` is a sequence of numbers, it should have same length as image dim (csg|]}qSr(r()rrrr(r)rsz#prepare_spacing..z;`spacing` is a sequence of elements with unsupported type: z[`spacing` should either be a number, a sequence of numbers or a sequence of sequences, got ) r_rHr4rrrandarrayrcr>rerrangerb)rNrrr()rrNr)r!s:   @ rr\)maxsizecCsFdddg}||||gdddg|||gdddg|||gdddgdddg||gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gd d d gdddgdddgdddggdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgd d d gdddgdddggdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggd d d gdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gd d d gdddgdddgdddggdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgd d d gdddgdddggdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gdddgdddg||gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddgdddggd d d gdddgdddgdddggdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddg|||gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddg||gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gd d d gdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gd d d gdddgdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddgdddgdddggd d d gdddgdddgdddggdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gd d d gdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddgdddgdddg|gdddgdddgdddgdddggd d d gdddgdddgdddggdddgdddgdddg|gdddgd d d gdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddgdddggdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddgdddg||gdddgdddgdddg|gdddgdddgdddg|gdddgdddg||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddgdddgdddg|gdddgdddg||gdddgdddg||gdddg|||gdddgdddg||gdddg|||gdddg|||g||||gg}tj||d S) a returns a lookup table. For every binary neighbour code (2x2x2 neighbourhood = 8 neighbours = 8 bits = 256 codes) it contains the surface normals of the triangles. The length of the normal vector encodes the surfel area. Adapted from https://github.com/deepmind/surface-distance created using the marching_cube algorithm see e.g. https://en.wikipedia.org/wiki/Marching_cubes Args: device: torch device to use for the table. gg?ggпg?g?gg?gؿrP)r1 as_tensor)r-r3r{r(r(r)$_get_neighbour_code_to_normals_tables  """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" rcCst|d}t|}tj|d|d|d|d|d|dggg||jd}tjj||dd}|d}|tjtdgg|dfS) a\ Returns an array mapping neighbourhood code to the surface elements area. Adapted from https://github.com/deepmind/surface-distance Note that the normals encode the initial surface area. This function computes the area corresponding to the given `spacing`. Args: spacing_mm: a sequence of 3 numbers. Voxel spacing along the first 3 spatial axes. device: device to put the table on. Returns: An array of size 256, mapping neighbourhood code to the surface area. ENCODING_KERNEL[3] which is the kernel used to compute the neighbourhood code. r\r&rrr,r]r/rP) rrr1rr.linalgnormr7ENCODING_KERNEL) spacing_mmr-crrZneighbour_code_to_surface_arear(r(r)+create_table_neighbour_code_to_surface_areas 0 rcCs&t|d}|\}}dtj|}tjdg|jd}||tdd<||tdd<||tdd<||tdd<||td d<d||td d<||td d<||td d<d||td d<||tdd<||tdd<||tdd<||tdd<||tdd<t||d}|tj t dgg|dfS)aU Returns an array mapping neighbourhood code to the contour length. Adapted from https://github.com/deepmind/surface-distance In 2D, each point has 4 neighbors. Thus, are 16 configurations. A configuration is encoded with '1' meaning "inside the object" and '0' "outside the object". For example, "0101" and "1010" both encode an edge along the first spatial axis with length spacing[0] mm; "0011" and "1100" both encode an edge along the second spatial axis with length spacing[1] mm. Args: spacing_mm: 2-element list-like structure. Pixel spacing along the 1st and 2nd spatial axes. device: device to put the table on. Returns: A 16-element array mapping neighbourhood code to the contour length. ENCODING_KERNEL[2] which is the kernel used to compute the neighbourhood code. rrrrRZ0001Z0010Z0011Z0100Z0101Z0110Z01111000Z1001Z1010Z1011Z1100Z1101Z1110rP) rrarrr3r.rHrr1rr)rr-firstseconddiagZ neighbour_code_to_contour_lengthr(r(r)-create_table_neighbour_code_to_contour_lengths(  rcCs4t|}t|t|d}|dkr*t||St||S)z returns a table mapping neighbourhood code to the surface area or contour length. Args: spacing: a sequence of 2 or 3 numbers, indicating the spacing in the spatial dimensions. device: device to put the table on. rr)rerrrr)rNr-rwr(r(r)r"/s  )r&TNT)r|N)r|NFFr])F)N)N)N)N)4 __future__rr functoolsrrtypesrtypingrrrnumpyrar1 monai.configr r Z#monai.transforms.croppad.dictionaryr monai.transforms.utilsr r monai.utilsr rrrrrrrrrrrr__all__rr6rrrrrr r!rrrrr"r(r(r(r) s~    0  >  i1;"A2   *