U Ph f2@sddlmZddlZddlZddlZddlmZmZmZm Z m Z ddl m Z ddl mZmZddlmZmZddlmZddlZddlZddlZddlmZmZdd lmZmZdd lm Z dd l!m"Z"dd l#m$Z$dd l%m&Z&m'Z'm(Z(ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4ddl5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;mZ>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJddlKmLZLddlMmNZNmOZOmPZPmQZQmRZReIddeH\ZSZTeId\ZUZVeId\ZWZXeId\ZYZZeIddd\Z[Z\eId\Z]Z^ddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dd?d@dAdBdCdDdEdFdGdHdIdJdKg2Z_dLddej`fdMdNdOdOdPdMdQdRdKZad!dNdTdUdVd6ZbdWdXdYd/ZcdNdNdNdNdNdTdZd[d0Zdd\dTd]d^d1Zed_d2ZfdWd`dTdadbd<ZgdcdLej`fdMdddddPdMdedfd7ZhdcdLej`fdWdddddgdWdedhd9ZiejjfdWdgdWdidjd8ZkdkdkdldmdndodZldcdpdqdWdrdNdTdsdtd:Zmd"dMdvdTdwdxdydZnd#dMdzdNd{d|d}d3Zod$dMdrdzdNdrd~ddd4Zpd%ddMd`ddddd;Zqd&dddkdTddddZrd'dd`dNdkdMdMddTdd dd*Zsd(dd`dkddddTdTdd dd)ZtddpeudeLjvfdkddTdPddMddd!ZwddpeufdkddTdPdddZxddpej`dfdkddTddddZydpeudeLjvfdkddTdgdddd ZzdeLjvfd`ddddMddd"Z{ej|ej}ej~fd`dddddMdddZdeLjvfd`dddMddd$Zej~fd`ddMdddZdeLjvfd`dddMddd#Zejfd`ddMdddZdeLjvfd`dddMddd%Zej~ejfd`ddMdddZe@ddpdudddefdddpfdMddddTdddd+Zd)ddrd`ddœdd-Zd*dd`d`dTdTdddƜdd.Zd+dMdTdddʜddCZd,dWddrdWd͜dd'Zd-dMdd`dNddМdd,Zd.ddMddNdNdd՜dd&Zd/d`ddTdd؜dd5Ze ddۜddZee8ee6Zd0dddߜddZddGZdkddddZd1dWdd`d`d`dWddd=ZGdd(d(Zd2dddd`ddd>Zdd?Zdd@ZdMddddAZdddddBZd3dTdddDZd4ddEZd5dTdddFZdwdddZddZddZd6dNdddZddZd d Zd d Zd dZedddeLjfddddHZd7ddddddZd8ddddddIZd9dduddMddTdTdzdzddTdd ddJZed kredS(:) annotationsN)CallableHashableIterableMappingSequence)contextmanager) lru_cachewraps) getmembersisclass)Any) DtypeLikeIndexSelection)NdarrayOrTensor NdarrayTensor)GaussianFilter) meshgrid_ij)Compose) MapTransform Transformapply_transform) any_np_ptascontiguousarraycumsumisfinitenonzeroravel searchsortedsoftplusunique unravel_indexwhere)GridSampleModeGridSamplePadModeInterpolateMode NdimageMode NumpyPadModePostFixPytorchPadMode SplineMode TraceKeysTraceStatusKeysdeprecated_arg_default ensure_tupleensure_tuple_repensure_tuple_sizefall_back_tupleget_equivalent_dtypeissequenceiterablelook_up_option min_versionoptional_import pytorch_after)TransformBackends)convert_data_typeconvert_to_cupyconvert_to_dst_typeconvert_to_numpyconvert_to_tensorzskimage.measurez0.14.2zskimage.morphologyz scipy.ndimagecupyndarraynamezskimage.exposureallow_missing_keys_modecheck_boundariescompute_divisible_spatial_sizeconvert_applied_interp_modecopypaste_arrayscheck_non_lazy_pending_opscreate_control_grid create_grid create_rotate create_scale create_shearcreate_translateextreme_points_to_image fill_holesFourier#generate_label_classes_crop_centers#generate_pos_neg_label_crop_centersgenerate_spatial_bounding_boxget_extreme_points$get_largest_connected_component_maskremove_small_objects img_bounds in_boundsis_empty is_positivemap_binary_to_indicesmap_classes_to_indicesmap_spatial_axes rand_choice rescale_arrayrescale_array_int_maxrescale_instance_array resize_centerweighted_patch_samples zero_margins equalize_hist!get_number_image_type_conversionsget_transform_backendsprint_transform_backendsconvert_pad_modeconvert_to_contiguousget_unique_labels scale_affine attach_hooksync_meta_info reset_ops_idresolves_modeshas_status_keysdistance_transform_edt soft_clip?rfloatz$NdarrayOrTensor | float | int | NonezDtypeLike | torch.dtype)arrsharpness_factorminvmaxvdtypereturncCsb|dk rt||d^}}|}|dk r>|t| |||}|dk r^|t||||}|S)a Apply soft clip to the input array or tensor. The intensity values will be soft clipped according to f(x) = x + (1/sharpness_factor)*softplus(- c(x - minv)) - (1/sharpness_factor)*softplus(c(x - maxv)) From https://medium.com/life-at-hopper/clip-it-clip-it-good-1f1bf711b291 To perform one-sided clipping, set either minv or maxv to None. Args: arr: input array to clip. sharpness_factor: the sharpness of the soft clip function, default to 1. minv: minimum value of target clipped array. maxv: maximum value of target clipped array. dtype: if not None, convert input array to dtype before computation. Nrz)r9r)rvrwrxryrz_vrK/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/transforms/utils.pyrss?bool)probr{cCstt|kS)zv Returns True if a randomly chosen number is less than or equal to `prob`, by default this is a 50/50 chance. )rrandom)rrrrr^sz np.ndarrayimgcCsNtj|dd}tj|dd}tt|dddgt|dddgfS)zt Returns the minimum and maximum indices of non-zero lines in axis 0 of `img`, followed by that for axis 1. r)axis)npany concatenater")rax0ax1rrrrWs)xymarginmaxxmaxyr{cCs<t||ko||kno8||ko4||knS)zc Returns True if (x,y) is within the rectangle (margin, margin, maxx-margin, maxy-margin). )r)rrrrrrrrrXsznp.ndarray | torch.Tensor)rr{cCs||k S)zd Returns True if `img` is empty, that is its maximum value is not greater than its minimum. )maxminrrrrrYscCs|dkS)z{ Returns a boolean version of `img` where the positive values are converted into True, the other values are False. rrrrrrrZsint)rrr{cCst|ddddd|fsBt|dddd| dfrFdSt|ddd|ddf ot|dd| dddf S)zo Returns True if the values within `margin` indices of the edges of `img` in dimensions 1 and 2 are 0. NF)rr)rrrrrrdsBz float | None)rvrxryrzr{cCsx|dk rt||d^}}|}|}||krD|dk r@||S|S||||}|dksd|dkrh|S||||S)a Rescale the values of numpy array `arr` to be from `minv` to `maxv`. If either `minv` or `maxv` is None, it returns `(a - min_a) / (max_a - min_a)`. Args: arr: input array to rescale. minv: minimum value of target rescaled array. maxv: maximum value of target rescaled array. dtype: if not None, convert input array to dtype before computation. Nr|)r9rr)rvrxryrzr}Zminamaxanormrrrr_srcCsBt|j|p|j}t|jdD]}t|||||||<q"|S)zT Rescale each array slice along the first dimension of `arr` independently. r)rzerosshaperzranger_)rvrxryrzoutirrrras)rvrzr{cCs0t|p |j}tjt||j|j|p*|jdS)zc Rescale the array `arr` to be between the minimum and maximum values of the type `dtype`. r|)riinforzasarrayr_rr)rvrzinforrrr` sz Sequence[int]zSequence[int | None]z+tuple[tuple[slice, ...], tuple[slice, ...]]) srccenter destcenterdimsr{c Cst|}t|}tdg|}tdg|}tt||||||D]|\} } } } } }|rBt|ddt| | }t|dddt| | | | }t| || ||| <t| || ||| <qBt|t|fS)a Calculate the slices to copy a sliced area of array in `src_shape` into array in `dest_shape`. The area has dimensions `dims` (use 0 or None to copy everything in that dimension), the source area is centered at `srccenter` index in `src` and copied into area centered at `destcenter` in `dest`. The dimensions of the copied area will be clipped to fit within the source and destination arrays so a smaller area may be copied than expected. Return value is the tuples of slice objects indexing the copied area in `src`, and those indexing the copy area in `dest`. Example .. code-block:: python src_shape = (6,6) src = np.random.randint(0,10,src_shape) dest = np.zeros_like(src) srcslices, destslices = copypaste_arrays(src_shape, dest.shape, (3, 2),(2, 1),(3, 4)) dest[destslices] = src[srcslices] print(src) print(dest) >>> [[9 5 6 6 9 6] [4 3 5 6 1 2] [0 7 3 2 4 1] [3 0 0 1 5 1] [9 4 7 1 8 2] [6 6 5 8 6 7]] [[0 0 0 0 0 0] [7 3 2 4 0 0] [0 0 1 5 0 0] [4 7 1 8 0 0] [0 0 0 0 0 0] [0 0 0 0 0 0]] Nrr)lensliceziprrcliprtuple)Z src_shapeZ dest_shaperrrZs_ndimZd_ndim srcslices destslicesrssdsscdcdimd1d2rrrrFs&&$T) fill_valueinplace int | None)r resize_dimsrrc Gstt||j}t|jd}t|d}t|j||||\}}|slt|||j}||||<|S||S)a Resize `img` by cropping or expanding the image from the center. The `resize_dims` values are the output dimensions (or None to use original dimension of `img`). If a dimension is smaller than that of `img` then the result will be cropped and if larger padded with zeros, in both cases this is done relative to the center of `img`. The result is a new image with the specified dimensions and values from `img` copied into its center. r)r1rrrtolistrFfullrz) rrrrZhalf_img_shapeZhalf_dest_shaperrdestrrrrbIs  Fz None | strNone) input_arrayrA raise_errorr{cCs>t|tjjr:|jr:d|pdd}|r0t|t|dS)aN Check whether the input array has pending operations, raise an error or warn when it has. Args: input_array: input array to be checked. name: an optional name to be included in the error message. raise_error: whether to raise an error, default to False, a warning message will be issued instead. zMThe input image is a MetaTensor and has pending operations, but the function z1 assumes non-lazy input, result may be incorrect.N) isinstancemonaidata MetaTensorpending_operations ValueErrorwarningswarn)rrArmsgrrrrG^s zNdarrayOrTensor | Nonez'tuple[NdarrayOrTensor, NdarrayOrTensor])labelimageimage_thresholdr{cCst|dd|jddkr&|dd}tt|d}t|}|dk rt|ddtt||kd}t||td^}}t||@}n t|}t|t dd^}}t|t dd^}}||fS) a Compute the foreground and background of input label data, return the indices after fattening. For example: ``label = np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])`` ``foreground indices = np.array([1, 2, 3, 5, 6, 7])`` and ``background indices = np.array([0, 4, 8])`` Args: label: use the label data to get the foreground/background information. image: if image is not None, use ``label = 0 & image > image_threshold`` to define background. so the output items will not map to all the voxels in the label. image_threshold: if enabled `image`, use ``image > image_threshold`` to determine the valid image content area and select background only in this area. r[r@rrNr|cpudevice) rGrrrrr;rr9torchr)rrr label_flat fg_indicesimg_flatr} bg_indicesrrrr[ss    zlist[NdarrayOrTensor])r num_classesrrmax_samples_per_classr{cCsDt|ddd}|dk r6t|ddt||kd}t|}|}|dkr^|dkrZtd|}g}t|D]} |dkrtt|| tdd} n t|| k} |dk r|| @} t|t j j rt j nd} tt| | t dd d} |r4t| |kr4t| dkr4ttdt| d|t} || | qj|| qj|S) a` Filter out indices of every class of the input label data, return the indices after fattening. It can handle both One-Hot format label and Argmax format label, must provide `num_classes` for Argmax label. For example: ``label = np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])`` and `num_classes=3`, will return a list which contains the indices of the 3 classes: ``[np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])]`` Args: label: use the label data to get the indices of every class. num_classes: number of classes for argmax label, not necessary for One-Hot label. image: if image is not None, only return the indices of every class that are within the valid region of the image (``image > image_threshold``). image_threshold: if enabled `image`, use ``image > image_threshold`` to determine the valid image content area and select class indices only in this area. max_samples_per_class: maximum length of indices in each class to reduce memory consumption. Default is None, no subsampling. r\r@NrrzSchannels==1 indicates not using One-Hot format label, must provide ``num_classes``.r|r output_typer)rGrrrrrr9rrrrrrTensorrrrroundlinspaceastyperappend)rrrrrrchannelsZ num_classes_indicescrrZ cls_indicesZ sample_idrrrr\s>    "" rzint | Sequence[int]znp.random.RandomState | Nonelist) spatial_sizew n_samplesr_stater{c sFt|dd|dkrtd|dkr.tj}tj|jtd}tjt||td}t ddt ||D}||}|jt |}|dk r|| 8}t|}|d rt|d r|d dkr|jdt||d }n*t|||^} } t|| |d d d }t||tjd^}} t||d t|^} fdd|DS)a Computes `n_samples` of random patch sampling locations, given the sampling weight map `w` and patch `spatial_size`. Args: spatial_size: length of each spatial dimension of the patch. w: weight map, the weights must be non-negative. each element denotes a sampling weight of the spatial location. 0 indicates no sampling. The weight map shape is assumed ``(spatial_dim_0, spatial_dim_1, ..., spatial_dim_n)``. n_samples: number of patch samples r_state: a random state container Returns: a list of `n_samples` N-D integers representing the spatial sampling location of patches. rcr@Nz w must be an ND array, got None.r|cssJ|]B\}}||kr,t|d|||dnt|d|ddVqdS)rrN)r).0rmrrr sz)weighted_patch_samples..rr)sizeT)rightrcsg|]}t|qSr)r!rrdiffv_sizerr sz*weighted_patch_samples..)rGrrr RandomStaterrrr1rrrrrrrrandintrr;rrminimum) rrrrimg_sizewin_sizesr~idxrr}rrrrcs,     z list[int]zSequence[int] | intz tuple[Any])centersrlabel_spatial_shape allow_smallerr{c Cst||d}tt||dkrR|s:td|d|dtddt||D}t|d}t|td |td tj }t |D]$\}}|||kr||d 7<qg}t|||D],\} } } t t | | | d } |t| qt|S) a~ Utility to correct the crop center if the crop size and centers are not compatible with the image size. Args: centers: pre-computed crop centers of every dim, will correct based on the valid region. spatial_size: spatial size of the ROIs to be sampled. label_spatial_shape: spatial shape of the original label data to compare with ROI. allow_smaller: if `False`, an exception will be raised if the image is smaller than the requested ROI in any dimension. If `True`, any smaller dimensions will be set to match the cropped size (i.e., no cropping in that dimension). defaultrzUThe size of the proposed random crop ROI is larger than the image size, got ROI size z and label image size z respectively.css|]\}}t||VqdSN)r)rlrrrrr!sz'correct_crop_centers..rr)r1rrsubtractrrr floor_dividearrayruint16 enumeraterrrrr.) rrrr valid_startZ valid_endrZvalid_sZ valid_centersrZv_sZv_eZcenter_irrrcorrect_crop_centerss"  ( rz tuple[tuple]) r num_samples pos_ratiorrr rand_staterr{c Cs|dkrtjjj}g}t|tr*t|n|}t|trBt|n|}t|dkrft|dkrftdt|dks~t|dkrt|dkrdnd}t dt|dt|d|dt |D]P} | |kr|n|} | t| } | | } t | |} |t| |||qt|S) a Generate valid sample locations based on the label with option for specifying foreground ratio Valid: samples sitting entirely within image, expected input shape: [C, H, W, D] or [C, H, W] Args: spatial_size: spatial size of the ROIs to be sampled. num_samples: total sample centers to be generated. pos_ratio: ratio of total locations generated that have center being foreground. label_spatial_shape: spatial shape of the original label data to unravel selected centers. fg_indices: pre-computed foreground indices in 1 dimension. bg_indices: pre-computed background indices in 1 dimension. rand_state: numpy randomState object to align with other modules. allow_smaller: if `False`, an exception will be raised if the image is smaller than the requested ROI in any dimension. If `True`, any smaller dimensions will be set to match the cropped size (i.e., no cropping in that dimension). Raises: ValueError: When the proposed roi is larger than the image. ValueError: When the foreground and background indices lengths are 0. NrzNo sampling location available.rzNum foregrounds z, Num backgrounds zD, unable to generate class balanced samples, setting `pos_ratio` to .)rr__self__rrrrrrrrrandrr!rrrr.)rrrrrrrrrr}indices_to_use random_intrcenterrrrrR4s&  zSequence[NdarrayOrTensor]zlist[float | int] | None) rrrrratiosrrrr{cCs\|dkrtjjj}|dkr*td|dtt|dkrDdgt|n|}t|t|krztdt|dt|dtdd|Drtd |dt|D]>\} } t| d kr|| d krd || <|rt d | d qg} |j t||t |t |d } | D]B} || } |t| }t| ||}| t||||qt| S)a^ Generate valid sample locations based on the specified ratios of label classes. Valid: samples sitting entirely within image, expected input shape: [C, H, W, D] or [C, H, W] Args: spatial_size: spatial size of the ROIs to be sampled. num_samples: total sample centers to be generated. label_spatial_shape: spatial shape of the original label data to unravel selected centers. indices: sequence of pre-computed foreground indices of every class in 1 dimension. ratios: ratios of every class in the label to generate crop centers, including background class. if None, every class will have the same ratio to generate crop centers. rand_state: numpy randomState object to align with other modules. allow_smaller: if `False`, an exception will be raised if the image is smaller than the requested ROI in any dimension. If `True`, any smaller dimensions will be set to match the cropped size (i.e., no cropping in that dimension). warn: if `True` prints a warning if a class is not present in the label. Nrz:num_samples must be an int number and greater than 0, got rzDrandom crop ratios must match the number of indices of classes, got z and css|]}|dkVqdS)rNrrrrrrsz6generate_label_classes_crop_centers..z/ratios should not contain negative number, got rzno available indices of class z7 to crop, setting the crop ratio of this class to zero.)rp)rrrrrr.rrrrrchoicersumrr!rrr)rrrrr rrrZratios_rrrclassesr r r rrrrQns6 "   $zSequence[float] | Noneztorch.device | None)rspacing homogeneousrzrr{cCsXt|t}|pt}|tjkr*t||||S|tjkrDt|||||Std|ddS)a compute a `spatial_size` mesh. - when ``homogeneous=True``, the output shape is (N+1, dim_size_1, dim_size_2, ..., dim_size_N) - when ``homogeneous=False``, the output shape is (N, dim_size_1, dim_size_2, ..., dim_size_N) Args: spatial_size: spatial size of the grid. spacing: same len as ``spatial_size``, defaults to 1.0 (dense grid). homogeneous: whether to make homogeneous coordinates. dtype: output grid data type, defaults to `float`. device: device to compute and store the output (when the backend is "torch"). backend: APIs to use, ``numpy`` or ``torch``. backend  is not supportedN)r4r8ruNUMPY_create_grid_numpyTORCH_create_grid_torchr)rrrrzrbackend_backend_dtyperrrrIs   )rrrrzcCsp|ptdd|D}ddt||D}tjtj|ddit|tjd}|sT|St|t|dd gS) z; compute a `spatial_size` mesh with the numpy API. css|] }dVqdSrtNrrr}rrrrsz%_create_grid_numpy..cSs<g|]4\}}t|d d||dd|t|qS)rt@)rrrrdrrrrrsz&_create_grid_numpy..indexingijr|Nr) rrrrmeshgridr2r?r ones_like)rrrrzrangescoordsrrrrs "r)rrrrcs`|ptdd|D}fddt||D}t|}|sFt|St|t|dfS)z; compute a `spatial_size` mesh with the torch API. css|] }dVqdSrrrrrrrsz%_create_grid_torch..c sJg|]B\}}tj|d d||dd|t|ttjdqS)rtrrrz)rrrr2rr r(rrrs z&_create_grid_torch..r)rrrrstackr%)rrrrzrr&r'rr(rrs    rzSequence[float]) spatial_shaperrrzrc Cst|ttjk}|rtjntj}g}t||D]x\} } |rHtj| |dnt| } | ddkr| || dd| dddq.| || dd| ddq.t ||||||dS) zB control grid with two additional point in each direction rrrrtrrg@)rrrrzrr) r4r8rrceilrr as_tensorrrrI) r*rrrzrrZ torch_backendZ ceil_funcZ grid_shaper!rrrrrHs  ($zSequence[float] | floatstr) spatial_dimsradiansrrr{cstt|t}|tjkr,t||tjtjtjdS|tjkr`t||fddfddfdddSt d|ddS) a create a 2D or 3D rotation matrix Args: spatial_dims: {``2``, ``3``} spatial rank radians: rotation radians when spatial_dims == 3, the `radians` sequence corresponds to rotation in the 1st, 2nd, and 3rd dim respectively. device: device to compute and store the output (when the backend is "torch"). backend: APIs to use, ``numpy`` or ``torch``. Raises: ValueError: When ``radians`` is empty. ValueError: When ``spatial_dims`` is not one of [2, 3]. )r.r/sin_funccos_funceye_funccsttj|tjdSN)rzr)rsinr,float32thrrr1zcreate_rotate..csttj|tjdSr3)rcosr,r5r6rrrr82r9cstj|dSNrreyerankrrrr83r9rrN) r4r8r_create_rotaterr4r:r=rr)r.r/rrrrrrrJs$      r)r.r/r0r1r2r{c Cst|}|dkrpt|dkrh||d||d}}|d}|| |d<|d<|||d<|d<|Std |dkrd}t|dkr||d||d}}|d }|| |d<|d <|||d <|d <t|dkrB||d||d}}|dkr td|d } ||| d<| d<| || d<| d <|| }t|dkr||d||d}}|dkr|td|d } || | d<| d<||| d<| d<|| }|dkrtd |Std|ddS)Nrrr)rrrrrr)rrzradians must be non empty.rrrr)rrzAffine should be a matrix.rrrrzUnsupported spatial_dims: z, available options are [2, 3].)r.rr) r.r/r0r1r2sin_cos_raffine_affinerrrr@8sH      r@)r.coefsrr{csXt|t}|tjkr$t||tjdS|tjkrDt||fdddStd|ddS)a create a shearing matrix Args: spatial_dims: spatial rank coefs: shearing factors, a tuple of 2 floats for 2D, a tuple of 6 floats for 3D), take a 3D affine as example:: [ [1.0, coefs[0], coefs[1], 0.0], [coefs[2], 1.0, coefs[3], 0.0], [coefs[4], coefs[5], 1.0, 0.0], [0.0, 0.0, 0.0, 1.0], ] device: device to compute and store the output (when the backend is "torch"). backend: APIs to use, ``numpy`` or ``torch``. Raises: NotImplementedError: When ``spatial_dims`` is not one of [2, 3]. )r.rMr2cstj|dSr;r<r>rrrr8r9zcreate_shear..rrN)r4r8r _create_shearrr=rr)r.rMrrrrrrrLgs    )r.rMr{cCs|dkr.rrN)r4r8r _create_scalerrWrr)r.rTrrrrrrrKs    )r.rTr{cCs"t||dd}||d|dS)NrtrOrt)r0rUrrrrYsrY)r.shiftrr{csnt|t}t|}|tjkr0t||tjtjdS|tjkrZt||fddfdddSt d|ddS)a* create a translation matrix Args: spatial_dims: spatial rank shift: translate pixel/voxel for every spatial dim, defaults to 0. device: device to compute and store the output (when the backend is "torch"). backend: APIs to use, ``numpy`` or ``torch``. )r.r[r2rVcstjt|dSr;)rr=r,rXrrrr8r9z"create_translate..cstj|dSr;)rr,rXrrrr8r9rrN) r4r8rr_create_translaterr=rrr)r.r[rrrrrrrMs     )r.r[r{cCsBt|}||d}t|d|D]\}}||||f<q$||S)Nr)r.r)r.r[r2rVrKrarrrr\s  r\rz1.2z1.5) old_default new_defaultsincereplacedzIndexSelection | Noneztuple[list[int], list[int]])r select_fnchannel_indicesrrr{cCst|dd|jdd}|dk r2|tt|n|}||d}t|j}t||}|D]}|dkr\td|dq\dg|} dg|} tt t t ||dD]\} } |} t| dkrt | | } | sdg|dg|fSt| | kd}|d|| }|d|| d}|rBt|d}t||| }t|tjr`|n|| | <t|tjr|n|| | <q| | fS) a Generate the spatial bounding box of foreground in the image with start-end positions (inclusive). Users can define arbitrary function to select expected foreground from the whole image or specified channels. And it can also add margin to every dim of the bounding box. The output format of the coordinates is: [1st_spatial_dim_start, 2nd_spatial_dim_start, ..., Nth_spatial_dim_start], [1st_spatial_dim_end, 2nd_spatial_dim_end, ..., Nth_spatial_dim_end] This function returns [0, 0, ...], [0, 0, ...] if there's no positive intensity. Args: img: a "channel-first" image of shape (C, spatial_dim1[, spatial_dim2, ...]) to generate bounding box from. select_fn: function to select expected foreground, default is to select values > 0. channel_indices: if defined, select foreground only on the specified channels of image. if None, select foreground on the whole image. margin: add margin value to spatial dims of the bounding box, if only 1 value provided, use it for all dims. allow_smaller: when computing box size with `margin`, whether to allow the image edges to be smaller than the final box edges. If `True`, the bounding boxes edges are aligned with the input image edges, if `False`, the bounding boxes edges are aligned with the final box edges. Default to `True`. rSr@rNrz0margin value should not be negative number, got rr)rGrrr.rrr/rr itertools combinationsreversedrrr"rrrrrdetachritem)rrbrcrrrrndimr box_startbox_enddiaxdtZarg_maxmin_dmax_drrrrSs4     $   &(r)r connectivitynum_componentsr{cCstd\}}to.|o.t|tjo.|jtdk}|rNt|}|jj }t }n&t sZt dt |tj^}} tj }t}|||dd\} } | |kr|t} n@| || } ||| ddd}|d|}|| |} t| || jdd S) aS Gets the largest connected component mask of an image. Args: img: Image to get largest connected component from. Shape is (spatial_dim1 [, spatial_dim2, ...]) connectivity: Maximum number of orthogonal hops to consider a pixel/voxel as a neighbor. Accepted values are ranging from 1 to input.ndim. If ``None``, a full connectivity of ``input.ndim`` is used. for more details: https://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.label. num_components: The number of largest components to preserve. z cucim.skimagerzSkimage.measure required.T)rqZ return_numNr)dstrzr)r6has_cprrrrr:shortmeasurercp has_measure RuntimeErrorr9rr?rrrargsortbincountisinr;rz)rrqrrskimage has_cucimuse_cpimg_rlibr}features num_featuresrnonzerosZfeatures_to_keeprrrrU%s& $    @z+Sequence[float] | float | np.ndarray | None)rmin_sizerqindependent_channels by_measurepixdimr{c Cs"tt|dkr|Sts td|rt|jdd}t|tjjrL|j }n&|dk r`t ||}nt dd|}t t |}|dkrt dd}t ||}n|dk rt dt|t j^} } |s| dk} n| | dkrtnt j} t| ||} t| |^} } |s|| } | S) a Use `skimage.morphology.remove_small_objects` to remove small objects from images. See: https://scikit-image.org/docs/dev/api/skimage.morphology.html#remove-small-objects. Data should be one-hotted. Args: img: image to process. Expected shape: C, H,W,[D]. Expected to only have singleton channel dimension, i.e., not be one-hotted. Converted to type int. min_size: objects smaller than this size are removed. connectivity: Maximum number of orthogonal hops to consider a pixel/voxel as a neighbor. Accepted values are ranging from 1 to input.ndim. If ``None``, a full connectivity of ``input.ndim`` is used. For more details refer to linked scikit-image documentation. independent_channels: Whether to consider each channel independently. by_measure: Whether the specified min_size is in number of voxels. if this is True then min_size represents a surface area or volume value of whatever units your image is in (mm^3, cm^2, etc.) default is False. pixdim: the pixdim of the input image. if a single number, this is used for all axes. If a sequence of numbers, the length of the sequence must be equal to the image dimensions. rzSkimage required.NzU`img` is not of type MetaTensor and `pixdim` is None, assuming affine to be identity.rZrzPInvalid `pixdim` value detected, set it to 1. Please verify the pixdim settings.z?`pixdim` is specified but not in use when computing the volume.)rr has_morphologyryrrrrrrr/rrrprodrr+r9r?rrrint32 morphologyrVr;) rrrqrrrsrZ_pixdimZ voxel_volumeimg_npr}out_nprrrrrVVs8     zint | Iterable[int] | Nonezset[int])r is_onehotdiscardr{cCsn|jd}|r"ddt|D}n(|dkr:td|dtt|}|dk rjt|D]}||qZ|S)aGet list of non-background labels in an image. Args: img: Image to be processed. Shape should be [C, W, H, [D]] with C=1 if not onehot else `num_classes`. is_onehot: Boolean as to whether input image is one-hotted. If one-hotted, only return channels with discard: Can be used to remove labels (e.g., background). Can be any value, sequence of values, or `None` (nothing is discarded). Returns: Set of labels rcSs h|]\}}|dkr|qS)r)r)rrrrrr s z$get_unique_labels..rz7If input not one-hotted, should only be 1 channel, got rN)rrrsetr rr.r)rrr n_channelsapplied_labelsrrrrrks   zIterable[int] | None)img_arrrrqr{c Csd}|j|}|dk}|jd}t||p,|}|dk r@t|nt||}d}|||D]t} tj|jddt d} tj | |d|rt || n |d| kdd| d|rt | || <q\| |dt | f<q\|S)a Fill the holes in the provided image. The label 0 will be treated as background and the enclosed holes will be set to the neighboring class label. What is considered to be an enclosed hole is defined by the connectivity. Holes on the edge are always considered to be open (not enclosed). Note: The performance of this method heavily depends on the number of labels. It is a bit faster if the list of `applied_labels` is provided. Limiting the number of `applied_labels` results in a big decrease in processing time. If the image is one-hot-encoded, then the `applied_labels` need to match the channel index. Args: img_arr: numpy array of shape [C, spatial_dim1[, spatial_dim2, ...]]. applied_labels: Labels for which to fill holes. Defaults to None, that is filling holes for all labels. connectivity: Maximum number of orthogonal hops to consider a pixel/voxel as a neighbor. Accepted values are ranging from 1 to input.ndim. Defaults to a full connectivity of ``input.ndim``. Returns: numpy array of shape [C, spatial_dim1[, spatial_dim2, ...]]. rrNr|r) structure iterationsmaskorigin border_valueoutput) rrindimagegenerate_binary_structurerrkrrrrbinary_dilation logical_not) rrrqZ channel_axis num_channelsZ is_one_hotr.rZbackground_labelrtmprrrrOs.    zlist[tuple[int, ...]])rr backgroundpertr{cstdddkrtjjjt|ktddkrDtdfdd}g}tjD]<}| t || || t || |qd|S)a Generate extreme points from an image. These are used to generate initial segmentation for annotation models. An optional perturbation can be passed to simulate user clicks. Args: img: Image to generate extreme points from. Expected Shape is ``(spatial_dim1, [, spatial_dim2, ...])``. rand_state: `np.random.RandomState` object used to select random indices. background: Value to be consider as background, defaults to 0. pert: Random perturbation amount to add to the points, defaults to 0.0. Returns: A list of extreme points, its length is equal to 2 * spatial dimension of input image. The output format of the coordinates is: [1st_spatial_dim_min, 1st_spatial_dim_max, 2nd_spatial_dim_min, ..., Nth_spatial_dim_max] Raises: ValueError: When the input image does not have any foreground pixel. rTr@Nrz1get_extreme_points: no foreground object in mask!cst||kd}t|tjr(|n|}dk r>|n|}g}tjD]X}t||ddk rv nd}t |d}t |j |d}| |qP|S)z Select one of the indices within slice containing val. Args: val : value for comparison dim : dimension in which to look for value rNrrr)r"rrrrrrrirr rrrr)valrrptjrrrrrr _get_points,  z&get_extreme_points.._get_point) rGrrrr"rrrrirrrr)rrrrrpointsrrrrrTs   z?Sequence[float] | float | Sequence[torch.Tensor] | torch.Tensorz torch.Tensor)rrsigma rescale_min rescale_maxr{c stjt|dtjd|D] }d|<qt|trJfdd|D}ntj|jd}ddt|j d|d}| d } }||||||S) a" Please refer to :py:class:`monai.transforms.AddExtremePointsChannel` for the usage. Applies a gaussian filter to the extreme points image. Then the pixel values in points image are rescaled to range [rescale_min, rescale_max]. Args: points: Extreme points of the object/organ. label: label image to get extreme points from. Shape must be (1, spatial_dim1, [, spatial_dim2, ...]). Doesn't support one-hot labels. sigma: if a list of values, must match the count of spatial dimensions of input data, and apply every value in the list to 1 spatial dimension. if only 1 value provided, use it for all spatial dimensions. rescale_min: minimum value of output data. rescale_max: maximum value of output data. rr|rtcsg|]}tj|jdqS)r)rr,r)rrZ points_imagerrrMsz+extreme_points_to_image..rr)r)r zeros_liker,rurrr unsqueezerrisqueezergrr) rrrrrrgaussian_filterZ min_intensityZ max_intensityrrrrN/s  zSequence[int] | int | None)img_ndim spatial_axes channel_firstr{cCs|dkr&t|rtd|n t|dSg}t|D]J}|rZ||dkrN||n|dq2||dkrv|d|dn|q2|S)ae Utility to map the spatial axes to real axes in channel first/last shape. For example: If `channel_first` is True, and `img` has 3 spatial dims, map spatial axes to real axes as below: None -> [1, 2, 3] [0, 1] -> [1, 2] [0, -1] -> [1, -1] If `channel_first` is False, and `img` has 3 spatial dims, map spatial axes to real axes as below: None -> [0, 1, 2] [0, 1] -> [0, 1] [0, -1] -> [0, -2] Args: img_ndim: dimension number of the target image. spatial_axes: spatial axes to be converted, default is None. The default `None` will convert to all the spatial axes of the image. If axis is negative it counts from the last to the first axis. If axis is a tuple of ints. channel_first: the image data is channel first or channel last, default to channel first. Nrr)rrr.r)rrrZ spatial_axes_r]rrrr]]s  $z=MapTransform | Compose | tuple[MapTransform] | tuple[Compose]) transformc cst|rt|}g}t|tr&|g}nt|trDdd|jD}t|dkrXtddd|D}z|D] }d|_ qldVW5t||D]\}}||_ qXdS)aTemporarily set all MapTransforms to not throw an error if keys are missing. After, revert to original states. Args: transform: either MapTransform or a Compose Example: .. code-block:: python data = {"image": np.arange(16, dtype=float).reshape(1, 4, 4)} t = SpatialPadd(["image", "label"], 10, allow_missing_keys=False) _ = t(data) # would raise exception with allow_missing_keys_mode(t): _ = t(data) # OK! cSsg|]}t|tr|qSr)rrrtrrrrs z+allow_missing_keys_mode..rz_allow_missing_keys_mode expects either MapTransform(s) or Compose(s) containing MapTransform(s)cSsg|] }|jqSr)allow_missing_keysrrrrrsTN) r3rrrflatten transformsr TypeErrorrr)rrZ orig_statesrZo_srrrrBs$    nearestz bool | Nonemode align_cornerscstttfr"fddDStts0Stdkrd}t|tsZ|tkrdd<n8t|dts~|dtkrfddttDd<dkrdkrt j nd}t |r؇fddDnd<dkr dkr fd d DSS) a Recursively change the interpolation mode in the applied operation stacks, default to "nearest". See also: :py:class:`monai.transform.inverse.InvertibleTransform` Args: trans_info: applied operation stack, tracking the previously applied invertible transform. mode: target interpolation mode to convert, default to "nearest" as it's usually used to save the mode output. align_corners: target align corner value in PyTorch interpolation API, need to align with the `mode`. csg|]}t|dqSrrE)rr)rrrrrsz/convert_applied_interp_mode..rrcsg|]}qSrrr)rrrrsrNcsg|]}qSrrr)_align_cornersrrrscs i|]}|t|dqSrr)rk)rr trans_inforr sz/convert_applied_interp_mode..) rrrrdictr _interp_modesrrr+NONEr3)rrrZ current_mode current_valuer)rrrrrrEs*   cCsxt|ttfrdd|DSt|tjjr:t|j|_|St|tsH|St |}t j |krft j |t j <dd| DS)zbfind MetaTensors in list or dict `data` and (in-place) set ``TraceKeys.ID`` to ``Tracekeys.NONE``.cSsg|] }t|qSrro)rr!rrrrsz reset_ops_id..cSsi|]\}}|t|qSrrrrr~rrrrsz reset_ops_id..)rrrrrrroapplied_operationsrrr+IDritems)rrrrros    )r*rcCs^t|dt|}g}t||D]4\}}|dkrFtt|||n|}||q t|S)aZ Compute the target spatial size which should be divisible by `k`. Args: spatial_shape: original spatial shape. k: the target k for each spatial dimension. if `k` is negative or 0, the original size is preserved. if `k` is an int, the same `k` be applied to all the input spatial dimensions. rr)r1rrrrr+rr)r*rnew_sizeZk_drnew_dimrrrrDs " znp.ndarray | None)rrnum_binsrrr{c Cs|j}|dk r |tj|tdn|}tr>t||\}}n0t||\}}|dd|ddd}|} t | ||d} t ||| }| |S)a Utility to equalize input image based on the histogram. If `skimage` installed, will leverage `skimage.exposure.histogram`, otherwise, use `np.histogram` instead. Args: img: input image to equalize. mask: if provided, must be ndarray of bools or 0s and 1s, and same shape as `image`. only points at which `mask==True` are used for the equalization. num_bins: number of the bins to use in histogram, default to `256`. for more details: https://numpy.org/doc/stable/reference/generated/numpy.histogram.html. min: the min value to normalize input image, default to `0`. max: the max value to normalize input image, default to `255`. Nr|rrr)rvrxry) rrrr has_skimageexposure histogramrrr_interpreshape) rrrrr orig_shapeZhist_imghistbinsZcumrrrresc@s@eZdZdZeddddddZed ddddd d d ZdS) rPz/ Helper class storing Fourier mappings rr)rr.r{cCstt| d}t|tjrlttjdrFtjjtjj||d|d}qt jjt jj| |d|d}nt jjt jj||d|d}|S)a? Applies fourier transform and shifts the zero-frequency component to the center of the spectrum. Only the spatial dimensions get transformed. Args: x: Image to transform. spatial_dims: Number of spatial dimensions. Returns k: K-space data. rfftshiftraxes) rrrrrhasattrfftrfftnrrnumpy)rr.rrrrr shift_fourier"s   &zFourier.shift_fourierNr)rr.n_dimsr{cCstt| d}t|tjrrttjdrJtjjtjj||d|ddj }qt jjt jj| |d|dj }nt jjt jj||d|dj }|S)a Applies inverse shift and fourier transform. Only the spatial dimensions are transformed. Args: k: K-space data. spatial_dims: Number of spatial dimensions. Returns: x: Tensor in image space. r ifftshiftrbackward)rrr) rrrrrrrifftnrrealrrr)rr.rrrrrrinv_shift_fourier;s   "(zFourier.inv_shift_fourier)N)__name__ __module__ __qualname____doc__ staticmethodrrrrrrrPs rr zHashable | None)r test_datakeyr{c sddlmdd}t|||ts(dnd}|j}t|sVtfdd|Dr^td|D]x}|||}t|}t|t j r|j nd } t |||j |j}|||} t| t j r| j nd } t| |r| | krb|d 7}qb|S) a Get the number of times that the data need to be converted (e.g., numpy to torch). Conversions between different devices are also counted (e.g., CPU to GPU). Args: transform: composed transforms to be tested test_data: data to be used to count the number of conversions key: if using dictionary transforms, this key will be used to check the number of conversions. rOneOfcSs|dkr |S||Srr)objrrrr _get_dataasz4get_number_image_type_conversions.._get_datarc3s|]}t|VqdSr)rrrrrrjsz4get_number_image_type_conversions..zRNot compatible with `OneOf`, as the applied transform is deterministically chosen.Nr)monai.transforms.composerrr-rrrrytyperrrr map_items unpack_items) rrrrZnum_conversionstr _transformZ prev_dataZ prev_type prev_deviceZ curr_dataZ curr_devicerrrrfUs      cCsji}g}ttjD]R\}}||kr$q||t|rt|tr|dkrtj|j ktj |j kg||<q|S)a6Get the backends of all MONAI transforms. Returns: Dictionary, where each key is a transform, and its corresponding values are a boolean list, stating whether that transform supports (1) `torch.Tensor`, and (2) `np.ndarray` as input without needing to convert. )BatchInverseTransformrCuCIMCuCIMD DecollatedInvertDInvertibleTransformLambdaLambdaDrr RandCuCIM RandCuCIMD RandomOrderPadListDataCollate RandLambda RandLambdaDRandTorchVisionDRandomizableTransform TorchVisionDr) r rrrr issubclassrr8rrr)backendsZunique_transformsnrrrrrgzs  c s$Gddd}dd|jffdd }t}t|}d\}}}}|dd d |D]v\}} t| rv|j} |d 7}n>| d r|j} |d 7}n&| d r|j} |d 7}n|j} |d 7}||| d | d | d qVtd|d||jd||jd||jd||jdS)z2Prints a list of backends of all MONAI transforms.c@seZdZdZdZdZdZdS)z(print_transform_backends..ColorsrZ91Z92Z93N)rrrnoneredgreenyellowrrrrColorssrcSstd|d|ddS)Nzz)print)rcolorrrr print_colorsz-print_transform_backends..print_colorcs$|dd|dd|d|dS)Nz<50 z<8r)rArrrrrrprint_table_columnsz4print_transform_backends..print_table_column)rrrrrzTorch?zNumpy?rr)rzTotal number of transforms:z1Number transforms allowing both torch and numpy: zNumber of TorchTransform: zNumber of NumpyTransform: zNumber of uncategorized: N) rrgrrallrrrr) rrrZn_totalZ n_t_or_npZn_tZn_npZn_uncategorizedrr~rrrrrhs2      z str | NonersrcCsxt|tjr0|dkrd}n |dkr&d}t|tSt|tjr`|dkrJd}n |dkrVd}t|tStdt |ddS)z Utility to convert padding mode between numpy array and PyTorch Tensor. Args: dst: target data to convert padding mode for, should be numpy array or PyTorch Tensor. mode: current padding mode. wrapcircularedge replicatezunsupported data type: rN) rrrr4r)rr?r'rrr!rrrris    z7NdarrayOrTensor | str | bytes | Mapping | Sequence[Any]z)NdarrayOrTensor | Mapping | Sequence[Any])rr{c snt|tjtjttfr"t|fSt|trBfdd| DSt|t rft |fdd|DS|SdS)a Check and ensure the numpy array or PyTorch Tensor in data to be contiguous in memory. Args: data: input data to convert, will recursively convert the numpy array or PyTorch Tensor in dict and sequence. kwargs: if `x` is PyTorch Tensor, additional args for `torch.contiguous`, more details: https://pytorch.org/docs/stable/generated/torch.Tensor.contiguous.html#torch.Tensor.contiguous. csi|]\}}|t|fqSrrjrkwargsrrrsz)convert_to_contiguous..c3s|]}t|fVqdSrr&rr'rrrsz(convert_to_contiguous..N) rrr?rrr-bytesrrrrr)rr(rr'rrjs    )centeredcCstt|t|}||kr(t|dStjddt||Dtd}t||}|r~t |d|dd|d|df<|S)aB Compute the scaling matrix according to the new spatial size Args: spatial_size: original spatial size. new_spatial_size: new spatial size. centered: whether the scaling is with respect to the image center (True, default) or corner (False). Returns: the scaling matrix. rcSs&g|]\}}t|tt|dqSr)rur)rorrrrrsz scale_affine..r|Nrr) rrrr=rrrurKrrW)rZnew_spatial_sizer*rrscalerrrrls &precsFddh}t||dkr"||n ||t|fdd}|S)z Adds `hook` before or after a `func` call. If mode is "pre", the wrapper will call hook then func. If the mode is "post", the wrapper will call func then hook. r-postcs||}||Srr)instr_funcZ_hookrrwrapper%s zattach_hook..wrapper)r4r )funchookr supportedr2rr0rrms  )rc Cs@t|ts|St|}t|}||kr8tjj||<t||tjjsltj||||<||||_|| ||jtj j |}||krtjj ||<||j||}}|s|||_||<|S|s|||_||<|S|rt|t|kr |n|}nt|t|kr&|n|}|||_||<|S)z Given the key, sync up between metatensor `data_dict[key]` and meta_dict `data_dict[key_transforms/meta_dict]`. t=True: the one with more applied_operations in metatensor vs meta_dict is the output, False: less is the output. )rrrr(metarrrget_default_metaupdaterTraceableTransform trace_keyget_default_applied_operationsrr) r data_dictrr!Z meta_dict_keyZ xform_keyZ from_meta from_dictrefrrrrn-s2  )r{cCs4t|tr(t|dkr(tdd|Ds0tddS)z0 Check boundaries for Signal transforms rcss|]}t|tVqdSr)rrurrrrrWsz#check_boundaries..z`. This function also accepts: * dictionaries of tensors * lists or tuples of tensors * list or tuples of dictionaries of tensors In any of the above scenarios, it iterates through the collections and executes itself recursively until it is operating on tensors. Args: data: a `torch.Tensor` or `MetaTensor` or collections of torch.Tensor or MetaTensor, as described above status_key: the status key to look for, from `TraceStatusKeys` default_message: a default message to use if the status key entry doesn't have a message set Returns: A tuple. The first entry is `False` or `True`. The second entry is the status messages that can be used for the user to help debug their pipelines. NrF)TN) rrrrqr{rrrrr|rvaluesr)rryrzZstatus_key_occurrencesr!r}reasonsoprrrrq!s"     ) block_paramsfloat64_distanceszNone | float | list[float]ztuple[int, int, int] | Nonez@None | NdarrayOrTensor | tuple[NdarrayOrTensor, NdarrayOrTensor]) rsamplingreturn_distancesreturn_indices distancesrrrr{c CsPtddd\}} to.| o.t|tjo.|jjdk} |s@|s@td|jdkrT|jdks\td||} } d \}}| rd \} }|r|rtj ntj }|d krtj |tj |d }n2t|tjs|j|jkrt d |j|kst d t|} |rXtj}|d krtj|f|j|d}n8t|tjs<|j|jkr s      4 \     8#    8&D43 ? A")2& A3J<=/#.$$8%2) %      21.