o  i @sddlmZddlZddlmZmZddlmZmZddl m Z ddl m Z ddl ZddlZddlmZmZddlmZdd lmZdd lmZmZmZmZmZmZmZm Z m!Z!e!d d d \Z"Z#e!d dd \ZZ#e!d dd \Z$Z#gdZ%d_ddZ&ej'fd`ddZ(edd d!d"d# $ %  &dadbd0d1Z) 2 dcddd6d7Z* 2  & & 8dedfd=d>Z+dgdBdCZ,dhdidFdGZ-djdLdMZ.dNdOgdPd$ggdQdRgdSdTggdNdOgdPd$gggdUZ/eddVdkdWdXZ0dkdYdZZ1dkd[d\Z2dkd]d^Z3dS)l) annotationsN)IterableSequence) lru_cachepartial) ModuleType)Any)NdarrayOrTensor NdarrayTensor)CropForegroundD)distance_transform_edt) MetricReductionconvert_to_cupyconvert_to_dst_typeconvert_to_numpyconvert_to_tensordeprecated_argensure_tuple_replook_up_optionoptional_importz scipy.ndimagebinary_erosionnamer distance_transform_cdt)ignore_backgrounddo_metric_reductionget_mask_edgesget_surface_distanceis_binary_tensorremap_instance_idprepare_spacingget_code_to_measure_tabley_predr yreturn#tuple[NdarrayTensor, NdarrayTensor]cCsT|jddkr|ddddfn|}|jddkr$|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(U/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/metrics/utils.pyr6s& &rf torch.Tensor reductionMetricReduction | str'tuple[torch.Tensor | Any, torch.Tensor]cCst|}|}tjd|jtjd}t|t}|tjkr"||fSd||<|tjkrc|j dd}t |dk|j dd||}|dkj dd}t |dk|j dd||}||fS|tj kr|j ddgd}tj |ddgd}||fS|tj kr|j dd}t |dk|j dd||}||fS|tj kr|j dd}|j dd}||fS|tjkr|j dd}t |dk|j dd||}||fS|tjkr|j dd}|j dd}||fS|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"].)torchisnanzerosr0floatrr NONEMEANsumwhereSUM MEAN_BATCH SUM_BATCH MEAN_CHANNEL SUM_CHANNEL ValueError)r*r,nansnot_nansZt_zeror(r(r)rGsL     ""  "  "   ralways_return_as_numpyz1.5.0z1.7.0zQThe option is removed and the return type will always be equal to the input type.)rsinceremoved msg_suffixr&TFseg_predr seg_gt label_idxintcropboolspacingSequence | NonecCs tddd\}}|j|jkrtd|jd|jdt|tjr-|s-tt|jd}t} nt }t } |duoB|oBt|tjoB|jj d k} |j t tj fvrO||k}|j t tj fvr[||k}|r||B} | s| j|jt d | j|jt d } } |dur~| | fS| | | | fS|d|d| dg}|dur| st|d t d \}}} n t|tjd \}}} td dgdddddd}|||| d}|d d|dd}}|dur| st ||gt d \}}t||A}t||A}nt||gt d \}}|||A}|||A}|||ft d St||jd\}}t|}|dkrtjjjntjjj}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. The default value is changed from `True` to `False` in v1.5.0. zcucim.skimage.morphologyrrz1seg_pred and seg_gt should have same shapes, got z and .r0Ncudar1cpur/predgtsrcr&F) source_keymargin allow_smallerstart_coord_key end_coord_key)rUrVrWrr2) wrap_sequence)!rr'rA isinstancer4Tensorrrr0rnptyper1rManyr6float16r rrr!lennn functionalconv3dconv2dstackr7to index_selectviewrKreshape)rHrIrJrLrNrDZcucim_binary_erosionZhas_cucim_binary_erosion converterlibZ use_cucimZor_volrUrV channel_firstcroppercropped edges_prededges_gtZcode_to_area_tablek spatial_dimsconvvolZ code_predZcode_gtall_onesZ areas_predZareas_gtretr(r(r)rsl,   "         r euclideandistance_metricstr7int | float | np.ndarray | Sequence[int | float] | NonecCst|tjrtnt}|stj|j||jd}nD||s8tj|j||jd}||}t|||j ddS|dkrHt |d|dd}n|dvrVt 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. rSrr})N.)sampling> chessboardtaxicab)metriczdistance_metric z is not implemented.)r`r4rarbrdinf ones_likefloat32rr1monai_distance_transform_edtrrrA)rHrIr~rNrqdisr(r(r)rs rr^ use_subvoxels symmetric class_indextuple[tuple[torch.Tensor, torch.Tensor], tuple[torch.Tensor, torch.Tensor] | tuple[torch.Tensor], tuple[torch.Tensor, torch.Tensor] | tuple[()]]c Csd}|r|dur |ndgt|j}t||d|dd^}} } | s1td|dkr+|ndd |sDtd |dkr>|ndd |rUt|| ||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)rLrNrDzthe ground truth of class r^Unknownz/ is all 0, this may result in nan/inf distance.zthe prediction of class rQ) rfr'rrdwarningswarnrrtupler0) r"r#r~rNrrrZ edges_spacingrurvareas distancesr(r(r)get_edge_surface_distance s(     rinputrNonecCs\t|tjs t|dt||kr"|dks"|dkr,t |ddSdS)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`r4rarAallbytemaxminrr)rrr(r(r)r[s *rrUby_sizec st}dd|D}|sS|r0fdd|D}t||}t|dddd}t|\}}tjtjd}t|D] \}} |d || k<q<|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) z%remap_instance_id..csg|]}|kqSr()r:)r instance_idrUr(r)rrcSs|dS)Nr&r()xr(r(r)sz#remap_instance_id..T)keyreverserSr&)listuniquezipsortedr4 zeros_likerK enumerate) rUrZpred_idZ instance_sizeZ pair_dataZ pair_list_Znew_predidxrr(rr)rns   r\int | float | np.ndarray | Sequence[int | float | np.ndarray | Sequence[int | float]] | None batch_sizeimg_dimASequence[None | int | float | np.ndarray | Sequence[int | float]]csbdus tttfrtg|StttjfrtfddtDr/tddtdttjfryt |krJtd|ddtfd dtDrbtd ddt d dtDsutd dtStdttfrt krtd ddfddt |DStdt dtdd)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`rcrsrNr(r) s"z"prepare_spacing..zEif `spacing` is a sequence, its elements should be of same type, got rPrzcif `spacing` is a sequence of sequences, the outer sequence should have same length as batch size (z), got c3s|] }t|kVqdSN)rfr)rr(r)rszKeach element of `spacing` list should either have same length asimage dim (css,|]}t|D] }t|ttfVqqdSr)rr`rKr7)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`rKr7rrrbndarrayrdrArfrrangerc)rNrrr()rrNr)r sV   r @ rr])maxsizecCsgd}g||||ggd|||ggd|||ggdgd||ggd|||ggdgd||ggdgd||ggd gd gd|ggd |||ggdgd ||ggd gd ||ggd gdgd|ggdgd||ggd gdgd|ggdgdgd |ggd gd ||ggd|||ggdgd||ggdgd||ggdgd gd|ggdgd||ggdgd gd|ggdgdgd|ggdgdgd gdggd gd||ggdgdgd |ggd gd gd|ggdgdgdgd ggdgdgd|ggdgdgdgdggdgdgdgdggdgdgd|ggd|||ggdgd||ggdgd||ggdgdgd |ggdgd||ggdgdgd|ggdgdgd|ggd!gd"gdgdggd gd||ggdgdgd |ggd#gdgd|ggd gd gdgdggdgdgd|ggd gdgdgdggdgd$gd gd%ggdgdgd|ggdgd||ggd&gdgd|ggd&gdgd'|ggd&gd||ggdgdgd|ggd(gd gdgdggdgdgdgdggdgdgd|ggd gdgd|ggd&gd gdgdggd)gdgdgd ggd&gd gd|ggdgdgdgdggdgdgd|ggdgdgd|ggdgd||ggd|||ggdgd||ggdgd||ggdgdgd|ggdgd||ggd*gdgd|ggdgdgd|ggd+gdgdgd%ggdgd ||ggdgdgd |ggdgd gd |ggd gdgdgdggd,gd'gd|ggd'gd'gdgdggd-gd$gdgd ggd gd'gd|ggd gd.||ggd#gdgd |ggdgd gd.|ggdgd/gdgd ggdgd gd|ggd#gd*||ggdgdgd gd*ggdgd gd*|ggd gd.gd |ggd#gdgdgdggd gd gd gd.ggdgdgd|ggdgd!gdgdggd#gdgd|ggdgdgd|ggdgd||ggdgd||ggdgdgd|ggdgdgd|ggdgdgd gdggdgdgd|ggd*gdgdgdggdgdgdgdggdgdgd|ggd gdgd|ggd gdgdgdggd#gdgdgdggdgdgd|ggd,gd'gdgdggdgdgd|ggdgdgd|ggdgd||ggd gd0gd|ggdgd gdgdggd+gdgdgd ggdgdgd |ggd!gdgdgdggd gdgd*|ggdgdgd|ggdgd||ggd gd gdgdggdgdgd|ggdgdgd|ggdgd||ggdgdgd|ggdgd||ggdgd||ggd|||ggd|||ggdgd||ggdgd||ggdgdgd|ggdgd||ggdgdgd|ggdgdgd|ggd gd gdgdggdgd||ggdgdgd|ggd gdgd*|ggd!gdgdgdggdgdgd |ggd+gdgdgd ggdgd gdgdggd gd0gd|ggdgd||ggdgdgd|ggdgdgd|ggd,gd'gdgdggdgdgd|ggd#gdgdgdggd gdgdgdggd gdgd|ggdgdgd|ggdgdgdgdggd*gdgdgdggdgdgd|ggdgdgd gdggdgdgd|ggdgdgd|ggdgd||ggdgd||ggdgdgd|ggd#gdgd|ggdgd!gdgdggdgdgd|ggdgdgdgdggd#gdgdgdggd gd.gd |ggdgd gd*|ggdgdgd gd*ggd#gd*||ggdgd gd|ggdgd/gdgd ggdgd gd.|ggd#gdgd |ggd gd.||ggd gd'gd|ggd-gd$gdgd ggd'gd'gdgdggd,gd'gd|ggd gdgdgdggdgd gd |ggdgdgd |ggdgd ||ggd+gdgdgd%ggdgdgd|ggd*gdgd|ggdgd||ggdgdgd|ggdgd||ggdgd||ggd|||ggdgd||ggdgdgd|ggdgdgd|ggdgdgdgdggd&gd gd|ggd)gdgdgd ggd&gd gdgdggd gdgd|ggdgdgd|ggdgdgdgdggd(gd gdgdggdgdgd|ggd&gd||ggd&gdgd'|ggd&gdgd|ggdgd||ggdgdgd|ggdgd$gd gd%ggd gdgdgdggdgdgd|ggd gd gdgdggd#gdgd|ggdgdgd |ggd gd||ggd!gd"gdgdggdgdgd|ggdgdgd|ggdgd||ggdgdgd |ggdgd||ggdgd||ggd|||ggdgdgd|ggdgdgdgdggdgdgdgdggdgdgd|ggdgdgdgd ggd gd gd|ggdgdgd |ggd gd||ggdgdgd gdggdgdgd|ggdgd gd|ggdgd||ggdgd gd|ggdgd||ggdgd||ggd|||ggd gd ||ggdgdgd |ggd gdgd|ggdgd||ggd gdgd|ggd gd ||ggdgd ||ggd |||ggd gd gd|ggdgd||ggdgd||ggd|||ggdgd||ggd|||ggd|||g||||g}tj||d1S)2a 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. )rr)?rr)rr)пrr)?r)rrr)rrr)rrr)?rr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)?rr)rrr)rrr)rrr)rrr)rrr)ؿrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrr)rrrrQ)r4 as_tensor)r0r6r|r(r(r)$_get_neighbour_code_to_normals_tables        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 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^r2rQ) rrr4rr1linalgnormr:ENCODING_KERNEL) spacing_mmr0crrZneighbour_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. rrrrSZ0001Z0010Z0011Z0100Z0101Z0110Z01111000Z1001Z1010Z1011Z1100Z1101Z1110rQ) rrbrrr6r1rKrr4rr)rr0firstseconddiagZ neighbour_code_to_contour_lengthr(r(r)-create_table_neighbour_code_to_contour_lengths(  rcCs4t|}t|t|d}|dkrt||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)rfrrrr)rNr0rxr(r(r)r!-s   r!)r"r r#r r$r%)r*r+r,r-r$r.)r&TNF)rHr rIr rJrKrLrMrNrOrDrMr$r%)r}N) rHr rIr r~rrNrr$r )r}NFFr^)r"r+r#r+r~rrNrrrMrrMrrKr$r)rr+rrr$r)F)rUr+rrMr$r+)rNrrrKrrKr$rr)4 __future__rrcollections.abcrr functoolsrrtypesrtypingrnumpyrbr4 monai.configr r Z#monai.transforms.croppad.dictionaryr monai.transforms.utilsr r monai.utilsr rrrrrrrrrrr__all__rr9rrrrrrr rrrrr!r(r(r(r)sd     ,   > j 1 ;  "2A   *