o  iD@sddlmZddlZddlmZddlmZddlZddl Z ddl m Z m Z ddl mZmZmZmZmZmZmZddlmZddlmZmZmZmZmZmZdd lmZm Z m!Z!dd l"m#Z#dd l$m%Z%m&Z&e!d d d\Z'Z(e!ddd\Z)Z(e!ddd\Z*Z(e!ddd\Z+Z(e!ddd\Z,Z(e!ddd\Z-Z(gdZ.GdddeZ/GdddeZ0GdddeZ1GdddeZ2Gd d!d!eZ3Gd"d#d#eZ4Gd$d%d%eZ5Gd&d'd'eZ6Gd(d)d)eZ7Gd*d+d+eZ8Gd,d-d-eZ9dS).) annotationsN)Sequence)Callable) DtypeLikeNdarrayOrTensor) Activations AsDiscrete BoundingRect FillHolesGaussianSmoothRemoveSmallObjectsSobelGradients) Transform)maxmaximumminsumuniquewhere)TransformBackendsconvert_to_numpyoptional_import)ensure_tuple_rep)convert_to_dst_typeconvert_to_tensorz scipy.ndimagelabel)namezskimage.morphologydiskopeningzskimage.segmentation watershedzskimage.measure find_contourscentroid) WatershedGenerateWatershedMaskGenerateInstanceBorderGenerateDistanceMapGenerateWatershedMarkersGenerateSuccinctContourGenerateInstanceContourGenerateInstanceCentroidGenerateInstanceType!HoVerNetInstanceMapPostProcessing!HoVerNetNuclearTypePostProcessingc@s8eZdZdZejgZdejfdd d Z ddddZ d S)r"a Use `skimage.segmentation.watershed` to get instance segmentation results from images. See: https://scikit-image.org/docs/stable/api/skimage.segmentation.html#skimage.segmentation.watershed. Args: connectivity: an array with the same number of dimensions as image whose non-zero elements indicate neighbors for connection. Following the scipy convention, default is a one-connected array of the dimension of the image. dtype: target data content type to convert, default is np.int64.  connectivity int | NonedtyperreturnNonecC||_||_dSN)r.r0)selfr.r0r6l/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/apps/pathology/transforms/post/array.py__init__J zWatershed.__init__NimagermaskNdarrayOrTensor | NonemarkerscCs>t|}t|}t|}t||||jd}t|||jddS)a\ Args: image: image where the lowest value points are labeled first. Shape must be [1, H, W, [D]]. mask: optional, the same shape as image. Only points at which mask == True will be labeled. If None (no mask given), it is a volume of all 1s. markers: optional, the same shape as image. The desired number of markers, or an array marking the basins with the values to be assigned in the label matrix. Zero means not a marker. If None (no markers given), the local minima of the image are used as markers. )r=r;r.r0r)rrr.rr0)r5r:r;r=Z instance_segr6r6r7__call__Ns  zWatershed.__call__)r.r/r0rr1r2)NN)r:rr;r<r=r<r1r __name__ __module__ __qualname____doc__rNUMPYbackendnpint64r8r?r6r6r6r7r";s  r"c@s8eZdZdZejgZdddejfdddZ dddZ dS)r#az generate mask used in `watershed`. Only points at which mask == True will be labeled. Args: activation: the activation layer to be applied on the input probability map. It can be "softmax" or "sigmoid" string, or any callable. Defaults to "softmax". threshold: an optional float value to threshold to binarize probability map. If not provided, defaults to 0.5 when activation is not "softmax", otherwise None. min_object_size: objects smaller than this size (in pixel) are removed. Defaults to 10. dtype: target data content type to convert, default is np.uint8. softmaxN activationstr | Callable threshold float | Nonemin_object_sizeintr0rr1r2cCs||_d}d}d}t|tr(|dkrd}n"|dkr d}ntd|dt|r/|}n tdt|dt|||d|_|sI|durId }t ||d |_ |d kr\t |d |_ dSd|_ dS) NFrITsigmoidJThe activation should be 'softmax' or 'sigmoid' string, or any callable. ' ' was given.7The activation type should be either str or callable. 'rIrQother?rMargmaxrmin_size) r0 isinstancestrlower ValueErrorcallabletyperrKr as_discreter remove_small_objects)r5rKrMrOr0 use_softmax use_sigmoid activation_fnr6r6r7r8ts(     "zGenerateWatershedMask.__init__prob_maprcCsf||}||}t|}t|d}|jdur||}t|dk}d||<t|||jddS)zk Args: prob_map: probability map of segmentation, shape must be [C, H, W, [D]] rNr-r>) rKrbrrrcrGrrr0)r5rgpredZ pred_indicesr6r6r7r?s     zGenerateWatershedMask.__call__) rKrLrMrNrOrPr0rr1r2)rgrr1r) rArBrCrDrrErFrGuint8r8r?r6r6r6r7r#ds  $r#c@s4eZdZdZejgZdejfdd d Z dddZ dS)r$a Generate instance border by hover map. The more parts of the image that cannot be identified as foreground areas, the larger the grey scale value. The grey value of the instance's border will be larger. Args: kernel_size: the size of the Sobel kernel. Defaults to 5. dtype: target data type to convert to. Defaults to np.float32. Raises: ValueError: when the `mask` shape is not [1, H, W]. ValueError: when the `hover_map` shape is not [2, H, W].  kernel_sizerPr0rr1r2cCs||_t|d|_dS)Nrk)r0r sobel_gradient)r5rkr0r6r6r7r8szGenerateInstanceBorder.__init__r;r hover_mapcCst|jdkrtd|jdt|jdkr*|jddkr)td|jddnt|jdkr6|d}n td |jd|jddkrPtd |jd|ddd f}|ddd f}t|t|}}t|t|}}||dks~||dkrtd ||||}||||}||d } ||d} t| t| } } t| t| } }| | dks|| dkrtdd| | | | } d| | || } t| | }|d|}d||dk<t|||jddS)a Args: mask: binary segmentation map, the output of :py:class:`GenerateWatershedMask`. Shape must be [1, H, W] or [H, W]. hover_map: horizontal and vertical distances of nuclear pixels to their centres of mass. Shape must be [2, H, W]. The first and second channel represent the horizontal and vertical maps respectively. For more details refer to papers: https://arxiv.org/abs/1812.06499. z:The hover map should have the shape of [C, H, W], but got .rr-/The mask should have only one channel, but got N?The mask should have the shape of [1, H, W] or [H, W], but got z5Suppose the hover map only has two channels, but got .z.Not a valid hover map, please check your input)r-.)r.zNot a valid sobel gradient mapr>) lenshaper_rrrmrrr0)r5r;rnZhover_hZhover_vZ hover_h_minZ hover_h_maxZ hover_v_minZ hover_v_maxZsobelhZsobelvZ sobelh_minZ sobelh_maxZ sobelv_minZ sobelv_maxZoverallr6r6r7r?s>     zGenerateInstanceBorder.__call__N)rkrPr0rr1r2)r;rrnrr1r rArBrCrDrrErFrGfloat32r8r?r6r6r6r7r$s r$c@s4eZdZdZejgZdejfdd d Z dddZ dS)r%a Generate distance map. In general, the instance map is calculated from the distance to the background. Here, we use 1 - "instance border map" to generate the distance map. Nuclei values form mountains so invert them to get basins. Args: smooth_fn: smoothing function for distance map, which can be any callable object. If not provided :py:class:`monai.transforms.GaussianSmooth()` is used. dtype: target data type to convert to. Defaults to np.float32. N smooth_fnCallable | Noner0rr1r2cCs|dur|nt|_||_dSr4)r rxr0)r5rxr0r6r6r7r8s zGenerateDistanceMap.__init__r;rinstance_bordercCst|jdkr|jddkrtd|jddnt|jdkr&|d}n td|jd|jddks;|jdkrCtd |jd ||}||}t| ||jd dS) 3 Args: mask: binary segmentation map, the output of :py:class:`GenerateWatershedMask`. Shape must be [1, H, W] or [H, W]. instance_border: instance border map, the output of :py:class:`GenerateInstanceBorder`. Shape must be [1, H, W]. rorr-rqrprrNrs@Input instance_border should be with size of [1, H, W], but got ?r>)rtrur_ndimrxrr0)r5r;rz distance_mapr6r6r7r?s   zGenerateDistanceMap.__call__)rxryr0rr1r2r;rrzrr1rrvr6r6r6r7r%s  r%c@s:eZdZdZejgZddddejfdddZ dddZ dS)r&a" Generate markers to be used in `watershed`. The watershed algorithm treats pixels values as a local topography (elevation). The algorithm floods basins from the markers until basins attributed to different markers meet on watershed lines. Generally, markers are chosen as local minima of the image, from which basins are flooded. Here is the implementation from HoVerNet paper. For more details refer to papers: https://arxiv.org/abs/1812.06499. Args: threshold: a float value to threshold to binarize instance border map. It turns uncertain area to 1 and other area to 0. Defaults to 0.4. radius: the radius of the disk-shaped footprint used in `opening`. Defaults to 2. min_object_size: objects smaller than this size (in pixel) are removed. Defaults to 10. postprocess_fn: additional post-process function on the markers. If not provided, :py:class:`monai.transforms.post.FillHoles()` will be used. dtype: target data type to convert to. Defaults to np.int64. 皙?rrrJNrMfloatradiusrPrOpostprocess_fnryr0rr1r2cCsH||_||_||_|durt}||_|dkrt|d|_dSd|_dS)NrrZ)rMrr0r rr rc)r5rMrrOrr0r6r6r7r81s"z!GenerateWatershedMarkers.__init__r;rrzcCst|jdkr|jddkrtd|jddnt|jdkr&|d}n td|jd|jddks;|jdkrCtd |j||jk}|t||d}t|dk}d||<||}t|}t | t |j }t |dd}|jdur||}t|||jd dS) r{rorr-rqrprrNrsr|r>)rtrur_r~rMrrrrrsqueezerrrrcr0)r5r;rzmarkerZmarker_indicesr6r6r7r?Bs(      z!GenerateWatershedMarkers.__call__) rMrrrPrOrPrryr0rr1r2rr@r6r6r6r7r&s r&c@s8eZdZdZdddZdd dZdddZdddZdS)r'aW Converts SciPy-style contours (generated by skimage.measure.find_contours) to a more succinct version which only includes the pixels to which lines need to be drawn (i.e. not the intervening pixels along each line). Args: height: height of bounding box, used to detect direction of line segment. width: width of bounding box, used to detect direction of line segment. Returns: the pixels that need to be joined by straight lines to describe the outmost pixels of the foreground similar to OpenCV's cv.CHAIN_APPROX_SIMPLE (counterclockwise) heightrPwidthr1r2cCr3r4)rr)r5rrr6r6r7r8rr9z GenerateSuccinctContour.__init__current np.ndarrayprevioustuple[int, int]cCs|d|d|d|df}d\}}|dvr*t|dd}t|d}||fS|dvr>t|d}t|d}||fS|dvrTt|d}t|dd}||fS|dkrht|dd}t|dd}||fS) aR Generate contour coordinates. Given the previous and current coordinates of border positions, returns the int pixel that marks the extremity of the segmented pixels. Args: current: coordinates of the current border position. previous: coordinates of the previous border position. rr-r))r})rWrW)r}rrW))rg)rW))rr)rr)rrW)rP)r5rrZp_deltarowcolr6r6r7_generate_contour_coordvs$      z/GenerateSuccinctContour._generate_contour_coordsequenceSequence[tuple[int, int]]cCs|d}|ddkr|d}|S|d|jdkr"|j|d}|S|d|jdkr9d|j|j|d}|Sd|j|j|d}|S)a Each sequence of coordinates describes a boundary between foreground and background starting and ending at two sides of the bounding box. To order the sequences correctly, we compute the distance from the top-left of the bounding box around the perimeter in a clockwise direction. Args: sequence: list of border points coordinates. Returns: the distance round the perimeter of the bounding box from the top-left origin rr-rr)rr)r5rZ first_coorddistancer6r6r7!_calculate_distance_from_top_lefts z9GenerateSuccinctContour._calculate_distance_from_top_leftcontourslist[np.ndarray]cCs g}g}gd}|D]G}g}d}d}d} t|D]*\} } | dkr| ddkrMd} dt| ddf} | d|jdkrBd|d<nl| ddkrLd|d<na| ddkr`d} t| dddf} nN| d|jdkrd } t| dt| ddf} | d|jdkrd|d <n'| d|jdkrd } t| ddt| df} n td | d dS|| | }n:| t|dkr|| |} | |kr|| | }n t | ||| d| kr|| |} | |kr|| | }| t|dkrB| dkr | ddkr d|| <n8| dkr| d|jdkrd|| <n$| d kr2| d|jdkr1d|| <n| d krB| ddkrBd|| <| }q| |} || |d q |ddurc|ddgd |ddury||jd|jdfgd |d dur||j|j|jd|jdfgd |d dur|d |j|j|jddfgd |j dddd}|D]$}|dd|kr| |rg||d}n|d}|d}q|d|kr| d|ddkr|| dt t|t jdS)a Args: contours: list of (n, 2)-ndarrays, scipy-style clockwise line segments, with lines separating foreground/background. Each contour is an ndarray of shape (n, 2), consisting of n (row, column) coordinates along the contour. )FFFFNrrrr-rWTrorrzInvalid contour coord z" is generated, skip this instance.)rrFrrcSs |dS)Nr)getxr6r6r7s z2GenerateSuccinctContour.__call__..)keyrrr>) enumeraterPrrwarningswarnappendrtrrGanyrsortpopfliprint32)r5rpixels sequencescornersgrouprZ last_addedprevcornericoordpixeldistlastZ _sequencer6r6r7r?s               *(  z GenerateSuccinctContour.__call__N)rrPrrPr1r2)rrrrr1r)rrr1rP)rrr1r)rArBrCrDr8rrr?r6r6r6r7r'ds   r'c@s0eZdZdZejgZddd d ZddddZdS)r(a  Generate contour for each instance in a 2D array. Use `GenerateSuccinctContour` to only include the pixels to which lines need to be drawn Args: min_num_points: assumed that the created contour does not form a contour if it does not contain more points than the specified value. Defaults to 3. contour_level: an optional value for `skimage.measure.find_contours` to find contours in the array. If not provided, the level is set to `(max(image) + min(image)) / 2`. roNmin_num_pointsrP contour_levelrNr1r2cCs||_||_dSr4)rr)r5rrr6r6r7r8(r9z GenerateInstanceContour.__init__r inst_maskroffsetSequence[int] | Nonenp.ndarray | NonecCs|}t|}t||jd}t|jd|jd}||}|dur$dS|jd|jkr7td|jddSt|jdkrJtt|jddS|dddf|d7<|dddf|d7<|S) z Args: inst_mask: segmentation mask for a single instance. Shape should be [1, H, W, [D]] offset: optional offset of starting position of the instance mask in the original array. Default to 0 for each dim. )levelrr-Nz< z) points don't make a contour, so skipped!rrz != 2, check for tricky shapes!) rrr rr'rurprintrt)r5rrZinst_contour_cvZgenerate_contourZ inst_contourr6r6r7r?,s z GenerateInstanceContour.__call__)roN)rrPrrNr1r2)r)rrrrr1r) rArBrCrDrrErFr8r?r6r6r6r7r(s  r(c@s2eZdZdZejgZefdddZddd dZ dS)r)z Generate instance centroid using `skimage.measure.centroid`. Args: dtype: the data type of output centroid. r0DtypeLike | Noner1r2cCs ||_dSr4r>)r5r0r6r6r7r8Ss z!GenerateInstanceCentroid.__init__rrrrSequence[int] | intcCsdt|}|d}t|j}t||}t|}t|D] }||||7<qt|||jddS)z Args: inst_mask: segmentation mask for a single instance. Shape should be [1, H, W, [D]] offset: optional offset of starting position of the instance mask in the original array. Default to 0 for each dim. rr>) rrrtrurr!rangerr0)r5rrr~Z inst_centroidrr6r6r7r?Vs    z!GenerateInstanceCentroid.__call__N)r0rr1r2)r)rrrrr1r) rArBrCrDrrErFrPr8r?r6r6r6r7r)Hs r)c@s"eZdZdZejgZdd d Zd S)r*zC Generate instance type and probability for each instance. type_predrseg_predbboxr instance_idrPr1tuple[int, float]cCs|\}}}}|d||||f} |d||||f} t| |k| tdd} | | } t| dd\} } tt| | } t| dddd} | dd} | dkr[t| dkr[| dd} d d | D}|| t| d }t | t |fS) ak Args: type_pred: pixel-level type prediction map after activation function. seg_pred: pixel-level segmentation prediction map after activation function. bbox: bounding box coordinates of the instance, shape is [channel, 2 * spatial dims]. instance_id: get instance type from specified instance id. rr>T) return_countscSs|dS)Nr-r6rr6r6r7rsz/GenerateInstanceType.__call__..)rreverser-cSsi|] }|d|dqS)rr-r6).0vr6r6r7 sz1GenerateInstanceType.__call__..gư>) flattenrboolrlistzipsortedrtrrPr)r5rrrrrminrmaxcmincmaxZ seg_map_cropZ type_map_cropZ inst_typeZ type_listZ type_pixels type_dict type_probr6r6r7r?ps    zGenerateInstanceType.__call__N) rrrrrrrrPr1r)rArBrCrDrrErFr?r6r6r6r7r*isr*csFeZdZdZ           d'd(fdd Zd)d%d&ZZS)*r+a The post-processing transform for HoVerNet model to generate instance segmentation map. It generates an instance segmentation map as well as a dictionary containing centroids, bounding boxes, and contours for each instance. Args: activation: the activation layer to be applied on the input probability map. It can be "softmax" or "sigmoid" string, or any callable. Defaults to "softmax". mask_threshold: a float value to threshold to binarize probability map to generate mask. min_object_size: objects smaller than this size (in pixel) are removed. Defaults to 10. sobel_kernel_size: the size of the Sobel kernel used in :py:class:`GenerateInstanceBorder`. Defaults to 5. distance_smooth_fn: smoothing function for distance map. If not provided, :py:class:`monai.transforms.intensity.GaussianSmooth()` will be used. marker_threshold: a float value to threshold to binarize instance border map for markers. It turns uncertain area to 1 and other area to 0. Defaults to 0.4. marker_radius: the radius of the disk-shaped footprint used in `opening` of markers. Defaults to 2. marker_postprocess_fn: post-process function for watershed markers. If not provided, :py:class:`monai.transforms.post.FillHoles()` will be used. watershed_connectivity: `connectivity` argument of `skimage.segmentation.watershed`. min_num_points: minimum number of points to be considered as a contour. Defaults to 3. contour_level: an optional value for `skimage.measure.find_contours` to find contours in the array. If not provided, the level is set to `(max(image) + min(image)) / 2`. device: target device to put the output Tensor data. rINrJrjrrrr-rorKrLmask_thresholdrNrOrPsobel_kernel_sizedistance_smooth_fnrymarker_thresholdr marker_radiusmarker_postprocess_fnwatershed_connectivityr/rrdevicestr | torch.device | Noner1r2c spt| |_t|||d|_t|d|_t|d|_t ||||d|_ t | d|_ t | | d|_t|_dS)N)rKrMrOrl)rx)rMrrrO)r.)rr)superr8rr#generate_watershed_maskr$generate_instance_borderr%generate_distance_mapr&generate_watershed_markersr"rr(generate_instance_contourr)generate_instance_centroid) r5rKrrOrrrrrrrrr __class__r6r7r8s$     z*HoVerNetInstanceMapPostProcessing.__init__nuclear_predictionrrntuple[dict, NdarrayOrTensor]cCs||}|||}|||}|||}||||}tt|dh}i} |D]O} || k} t| } | dd| dd| dd| dd| ddf} | dd| ddg} | t | | }|dur{| | | }| ||d| | <q,t ||j d}| |fS)a"post-process instance segmentation branches (NP and HV) to generate instance segmentation map. Args: nuclear_prediction: the output of NP (nuclear prediction) branch of HoVerNet model hover_map: the output of HV (hover map) branch of HoVerNet model rNr-rrro) bounding_boxr!contourr)rrrrrsetrGrr rr rrr)r5rrnZwatershed_maskZinstance_bordersrZwatershed_markers instance_mapZ instance_ids instance_infoinst_id instance_maskZ instance_bboxrZinstance_contourZinstance_centroidr6r6r7r?s0    4  z*HoVerNetInstanceMapPostProcessing.__call__) rINrJrjNrrrNr-roNN)rKrLrrNrOrPrrPrryrrrrPrryrr/rrPrrNrrr1r2)rrrnrr1rrArBrCrDr8r? __classcell__r6r6rr7r+s "r+cs6eZdZdZ    ddfdd ZdddZZS)r,a# The post-processing transform for HoVerNet model to generate nuclear type information. It updates the input instance info dictionary with information about types of the nuclei (value and probability). Also if requested (`return_type_map=True`), it generates a pixel-level type map. Args: activation: the activation layer to be applied on nuclear type branch. It can be "softmax" or "sigmoid" string, or any callable. Defaults to "softmax". threshold: an optional float value to threshold to binarize probability map. If not provided, defaults to 0.5 when activation is not "softmax", otherwise None. return_type_map: whether to calculate and return pixel-level type map. device: target device to put the output Tensor data. rINTrKrLrMrNreturn_type_maprrrr1r2cst||_||_t|_d}d}d}t|tr4|dkr#d}n"|dkr,d}nt d|dt |r;|}n t dt |dt |||d|_ |sU|durUd }t||d |_dS) NFrITrQrRrSrTrUrWrX)rr8rrr*generate_instance_typer\r]r^r_r`rarrKrrb)r5rKrMrrrdrerfrr6r7r8s,      z*HoVerNetNuclearTypePostProcessing.__init__type_predictionrrdict[int, dict]r#tuple[dict, NdarrayOrTensor | None]cCs||}||}d}|jrtt|j|d}|D].}|j||||d|d\}}|||d<|||d<|durJ||||k<t||j d}q||fS)aProcess NC (type prediction) branch and combine it with instance segmentation It updates the instance_info with instance type and associated probability, and generate instance type map. Args: instance_info: instance information dictionary, the output of :py:class:`HoVerNetInstanceMapPostProcessing` instance_map: instance segmentation map, the output of :py:class:`HoVerNetInstanceMapPostProcessing` type_prediction: the output of NC (type prediction) branch of HoVerNet model Nrr)rrrrrrar) rKrbrrtorchzerosrurrr)r5rrrtype_maprZ instance_typeZinstance_type_probr6r6r7r?'s&     z*HoVerNetNuclearTypePostProcessing.__call__)rINTN) rKrLrMrNrrrrr1r2)rrrrrrr1rrr6r6rr7r,s$r,): __future__rrcollections.abcrtypingrnumpyrGrmonai.config.type_definitionsrrmonai.transformsrrr r r r r monai.transforms.transformr0monai.transforms.utils_pytorch_numpy_unificationrrrrrr monai.utilsrrrmonai.utils.miscrmonai.utils.type_conversionrrr_rrrr r!__all__r"r#r$r%r&r'r(r)r*r+r,r6r6r6r7s@   $  )HE+H6/!&d