o  i@sddlmZddlZddlZddlZddlZddlZddlZddlZddl m Z m Z ddl m Z mZmZmZmZddlmZddlmZddlmZmZmZddlmZdd lmZddlZddl Z dd l!m"Z"dd l#m$Z$m%Z%m&Z&dd l'm(Z(dd l)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9e9d\Z:Z;e9ddd\ZdeiZ?dZ@ ddddZA   ddd)d*ZB ddd.d/ZC   0ddd3d4ZDdddd e-jEfdd=d>ZFdd@dAZGdddHdCZHddIdJdKZIdLdMZJddPdQZKddVdWZLdddXdYZMe,jNe-jOfdd[d\ZPd]d^ZQddadbZRddddeZSdfeTd fddkdlZUdmdnZVdodpZWdddudvZX 0ddd}d~ZYejZfdddZ[dddZ\  ddddZ]e+jOdde j^fdddZ_dddZ`   0 0 0ddddZa   0 0 0ddddZbddddZcdddZddddZeejffdddZgdddZh    dddd̄Ziddd΄Zjddd҄ZkdddՄZldddׄZmdddلZndS() annotationsN)abc defaultdict) GeneratorIterableMappingSequenceSizeddeepcopy)reduce)productstarmap zip_longest)PurePath)Any)default_collate)NdarrayOrTensor NdarrayTensorPathLike)MetaObj)MAX_SEED BlendModeMethod NumpyPadMode TraceKeysconvert_data_typeconvert_to_dst_type ensure_tupleensure_tuple_repensure_tuple_sizefall_back_tuplefirstget_equivalent_dtypeissequenceiterablelook_up_optionoptional_importpandas DataFrame)namenibabel)% AFFINE_TOLSUPPORTED_PICKLE_MODaffine_to_spacingcompute_importance_mapcompute_shape_offsetconvert_tables_to_dicts!correct_nifti_header_if_necessarycreate_file_basenamedecollate_batchdense_patch_slicesget_random_patchget_valid_patch_sizeis_supported_format iter_patchiter_patch_positioniter_patch_slices json_hashinglist_data_collate no_collationorientation_ras_lpspad_list_data_collatepartition_datasetpartition_dataset_classespickle_hashingrectify_header_sform_qformreorient_spatial_axesresample_datalistselect_cross_validation_foldsset_rnd sorted_dict to_affine_ndworker_init_fn zoom_affine remove_keysremove_extra_metadataget_extra_metadata_keys is_no_channelpickleMbP?dims Sequence[int] patch_size rand_statenp.random.RandomState | Nonereturntuple[slice, ...]csJ|durtjjn|jtfddt||D}tddt||DS)a, Returns a tuple of slices to define a random patch in an array of shape `dims` with size `patch_size` or the as close to it as possible within the given dimension. It is expected that `patch_size` is a valid patch for a source of shape `dims` as returned by `get_valid_patch_size`. Args: dims: shape of source array patch_size: shape of patch size to generate rand_state: a random state object to generate random numbers from Returns: (tuple of slice): a tuple of slice objects defining the patch Nc3s2|]\}}||krd||dndVqdS)rN.0mspsZrand_intrZR/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/data/utils.py |s0z#get_random_patch..cs"|] \}}t|||VqdSNslice)r\mcr^rZrZr`ra )nprandomrandinttuplezip)rRrTrU min_cornerrZr_r`r5isr5rZT image_sizeSequence[int] | int start_posoverlapSequence[float] | floatpaddedbool(Generator[tuple[slice, ...], None, None]ccsBt||}t|||||dD]}tddt||DVqdS)a Yield successive tuples of slices defining patches of size `patch_size` from an array of dimensions `image_size`. The iteration starts from position `start_pos` in the array, or starting at the origin if this isn't provided. Each patch is chosen in a contiguous grid using a rwo-major ordering. Args: image_size: dimensions of array to iterate over patch_size: size of patches to generate slices for, 0 or None selects whole dimension start_pos: starting position in the array, default is 0 for each dimension overlap: the amount of overlap of neighboring patches in each dimension (a value between 0.0 and 1.0). If only one float number is given, it will be applied to all dimensions. Defaults to 0.0. padded: if the image is padded so the patches can go beyond the borders. Defaults to False. Yields: Tuples of slice objects defining each patch )rorTrqrrrtcsrbrcrdr\sprZrZr`rargz$iter_patch_slices..N)r6r9rkrl)rorTrqrrrt patch_size_positionrZrZr`r:s   r: scan_interval return_slicelist[tuple[slice, ...]]csNt}tt|g}t|D]:dkr"|dqttt}t fddt|D}||durK|dndqg}t|D],} g} t|| D]} | | } | t | | | d8} | | q_|| qUt ddt j |dd iDj} |rfd d| DSfd d| DS) a Enumerate all slices defining ND patches of size `patch_size` from an `image_size` input image. Args: image_size: dimensions of image to iterate over patch_size: size of patches to generate slices scan_interval: dense patch sampling interval return_slice: whether to return a list of slices (or tuples of indices), defaults to True Returns: a list of slice objects defining each patch rrYc3s0|]}|kr|VqdSrcrZr\dirorTr|rZr`ras.z%dense_patch_slices..NcSg|]}|qSrZ)flattenr\xrZrZr` z&dense_patch_slices..indexingijc&g|]}tfddt|DqS)c3s&|]\}}t|||VqdSrcrdr\rrxrTrZr`ras$0dense_patch_slices...rk enumeraterrrZr`r&cr)c3s$|] \}}|||fVqdSrcrZrrrZr`ra"rrrrrZr`rr)lenr6r rangeappendintmathceilfloatr"maxrhasarraymeshgridT)rorTr|r}num_spatial_dimsZscan_numnumZscan_dimstartsdimZ dim_startsidx start_idxoutrZrr`r4s,          "r4F Sequence[int] | int | np.ndarray-Sequence[float] | float | Sequence[int] | intc Cst|}t||}t||}t||}t|dtr'tddt||D}n tddt||D}|r7|n tddt||D}tt t|||} t | S)a_ Yield successive tuples of upper left corner of patches of size `patch_size` from an array of dimensions `image_size`. The iteration starts from position `start_pos` in the array, or starting at the origin if this isn't provided. Each patch is chosen in a contiguous grid using a rwo-major ordering. Args: image_size: dimensions of array to iterate over patch_size: size of patches to generate slices for, 0 or None selects whole dimension start_pos: starting position in the array, default is 0 for each dimension overlap: the amount of overlap of neighboring patches in each dimension. Either a float or list of floats between 0.0 and 1.0 to define relative overlap to patch size, or an int or list of ints to define number of pixels for overlap. If only one float/int number is given, it will be applied to all dimensions. Defaults to 0.0. padded: if the image is padded so the patches can go beyond the borders. Defaults to False. Yields: Tuples of positions defining the upper left corner of each patch rcss$|] \}}t|d|VqdS)?Nroundr\ryorZrZr`rarz&iter_patch_position..css|] \}}||VqdSrcrZrrZrZr`racss$|] \}}|t|dVqdS)rYNrrwrZrZr`rar) rr6r r isinstancerrkrlrrr ) rorTrqrrrtndimrzstepsend_posrangesrZrZr`r9s    r9arrr copy_backmode str | Nonepad_optsdict9Generator[tuple[NdarrayOrTensor, np.ndarray], None, None]c+spddlm}t|j|}t||j}t|ddt||jD} tfddt|| D} ddtt ||j| D} rj||fdd| D|d |} td dt|| D} td dt|j| D}n|} |} |j}t ||| | d D]$}rtd dt|| D}n tdd|D}| |t |fVqz|rtddt| |jD}| ||d<dSdS)a Yield successive patches from `arr` of size `patch_size`. The iteration can start from position `start_pos` in `arr` but drawing from a padded array extended by the `patch_size` in each dimension (so these coordinates can be negative to start in the padded region). If `copy_back` is True the values from each patch are written back to `arr`. Args: arr: array to iterate over patch_size: size of patches to generate slices for, 0 or None selects whole dimension. For 0 or None, padding and overlap ratio of the corresponding dimension will be 0. start_pos: starting position in the array, default is 0 for each dimension overlap: the amount of overlap of neighboring patches in each dimension (a value between 0.0 and 1.0). If only one float number is given, it will be applied to all dimensions. Defaults to 0.0. copy_back: if True data from the yielded patches is copied back to `arr` once the generator completes mode: available modes: (Numpy) {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} (PyTorch) {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. If None, no wrapping is performed. Defaults to ``"wrap"``. See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html requires pytorch >= 1.10 for best compatibility. pad_opts: other arguments for the `np.pad` or `torch.pad` function. note that `np.pad` treats channel dimension as the first dimension. Yields: Patches of array data from `arr` which are views into a padded array which can be modified, if `copy_back` is True these changes will be reflected in `arr` once the iteration completes. Note: coordinate format is: [1st_dim_start, 1st_dim_end, 2nd_dim_start, 2nd_dim_end, ..., Nth_dim_start, Nth_dim_end]] r)pad_ndcSg|]}t|qSrZ)rur\ryrZrZr`r6rziter_patch..c3s$|] \}}|r r |ndVqdSrNrZ)r\ryvrtrZr`ra7rziter_patch..cSsg|] \}}|r |ndqS)rnrZ)r\oprrZrZr`r8cSsg|]}||fqSrZrZrrZrZr`r;r)Zto_padrcs|] \}}||VqdSrcrZrwrZrZr`ra=rcsrrcrZrwrZrZr`raArrcss(|]\}}|j||j|fVqdSrcstartstop)r\coordryrZrZr`raJs&css|] }|j|jfVqdSrcr)r\rrZrZr`raLrcsrbrcrd)r\ryrxrZrZr`raQrg.N) Z#monai.transforms.croppad.functionalrr6shaper rrurkrlrr:rhr)rrTrqrrrrrrrzZis_vZ _pad_sizeZ_overlapZarrpadZstart_pos_paddedZ iter_sizeslicesZ coords_no_padrZrr`r8s0 /   r8tuple[int, ...]cCs*t|}t||}tddt||DS)a Given an image of dimensions `image_size`, return a patch size tuple taking the dimension from `patch_size` if this is not 0/None. Otherwise, or if `patch_size` is shorter than `image_size`, the dimension from `image_size` is taken. This ensures the returned patch size is within the bounds of `image_size`. If `patch_size` is a single number this is interpreted as a patch of the same dimensionality of `image_size` with that size in each dimension. css"|] \}}t||p |VqdSrcminr[rZrZr`ra`rgz'get_valid_patch_size..)rr rkrl)rorTrrzrZrZr`r6Us r6rY dev_collatelevelr logger_namestrc s |d}t|}d}|ddt|dkrdnd}t|tjrzt|dt|dWSt yb}z t|d|d d d |Dd |d WYd}~dSd}~wt y}z t|d|ddd |Dd |d WYd}~dSd}~ww|j dkr|j dkr|j dkr|j dvrt|dt dd |DdS|jdkr|Snt|ttttfr|St|tjri}|D]'t|ddt|dt fdd |Ddd|<q|St|tjrvt|} t| } z dd | DWn#t y<dd | D} t|d| d |d YdSwt|d d!tfd"d#Drht|d$d%|d t|} fd&d | DSt|d'|d!dS)(a Recursively run collate logic and provide detailed loggings for debugging purposes. It reports results at the 'critical' level, is therefore suitable in the context of exception handling. Args: batch: batch input to collate level: current level of recursion for logging purposes logger_name: name of logger to use for logging See also: https://pytorch.org/docs/stable/data.html#working-with-collate-fn r>N z ... z collate/stack a list of tensorsz E: z, type cSg|]}t|jqSrZtype__name__r\elemrZrZr`ryzdev_collate..z in collate()z, shape cSsg|]}|jqSrZ)rrrZrZr`r~snumpystr_string_)ndarraymemmapz% collate/stack a list of numpy arrayscSsg|]}t|qSrZ)torch as_tensorr\brZrZr`rrrrrZz collate dict key "z " out of z keyscg|]}|qSrZrZrkeyrZr`rrrYcSrrZ)rrrZrZr`rrcSrrZrrrZrZr`rrz E: type z collate list of sizes: .c3s|] }|dkVqdSrrZr\rx)sizesrZr`rarzdev_collate..z, collate list inconsistent sizes, got size: z , in collate(csg|] }t|ddqS)rYr)r)r\samplesrrZr`rz E: unsupported type in collate )rrrrTensorlogging getLoggercriticalstack TypeError RuntimeError __module__rrrrrrbytesrrriterlistanyrl) batchrrr elem_typeZl_strZ batch_streritZelstypes transposedrZ)rrrrr`rcsn $  $ $  &&" )collate_fn_mapcspddlm}||}dd|D}tjdd|Dr&fdd|D}t||_dd|D|_d|_|S) z Collate a sequence of meta tensor into a single batched metatensor. This is called by `collage_meta_tensor` and so should not be used as a collate function directly in dataloaders. r)collate_tensor_fncSg|]}|jp tjqSrZ)metarNONEr\rrZrZr`rz*collate_meta_tensor_fn..cSs"g|] }t|trt|qSrZ)rrsetkeysrrZrZr`r"cs.g|]ttrfddDntjqS)csi|]}||qSrZrZ)r\krrZr` rz5collate_meta_tensor_fn...)rrrrr\Zcommon_r r`rs.cSrrZ)applied_operationsrrrrZrZr`rrT)torch.utils.data._utils.collaterr intersectionrrr is_batch)rrrZcollatedZ meta_dictsrZr r`collate_meta_tensor_fns  rcsvttstt}t|trtSt|tr#fdd|DSt|ttfr7fddt t |DSt S)zcollate a sequence of meta tensor sequences/dictionaries into a single batched metatensor or a dictionary of batched metatensorcs$i|]tfddDqS)crrZrZrrrZr`rrz2collate_meta_tensor...collate_meta_tensorr rrr`r s$z'collate_meta_tensor..cs"g|] tfddDqS)crrZrZrrrZr`rrz2collate_meta_tensor...rr rrr`rrz'collate_meta_tensor..) rrNotImplementedErrorr"rrrrkrrrr)rZelem_0rZrr`rs   rrrc s\ddlm}ddlm}||ti|d}t|tr#dd|Dn|}dt}z't|t rJi}|D]}|fdd|D}|||<q3|WS||}|WSt y}} z!t | } d| vrpdurl| d d 7} | d 7} t |} t | | d} ~ wt y} z%t | } d | vrd | vrdur| d d 7} | d7} t |} t | | d} ~ ww)aI Enhancement for PyTorch DataLoader default collate. If dataset already returns a list of batch data that generated in transforms, need to merge all data to 1 list. Then it's same as the default collate behavior. Note: Need to use this collate if apply some transforms that can generate batch data. r)default_collate_fn_map) MetaTensorcSsg|] }|D]}|qqSrZrZ)r\rrrZrZr`rz%list_data_collate..NcrrZrZrrrZr`rrz equal sizez Collate error on the key 'z' of dictionary data.z MONAI hint: if your transforms intentionally create images of different shapes, creating your `DataLoader` with `collate_fn=pad_list_data_collate` might solve this problem (check its documentation).rrz MONAI hint: if your transforms intentionally create mixtures of torch Tensor and numpy ndarray, creating your `DataLoader` with `collate_fn=pad_list_data_collate` might solve this problem (check its documentation).)rrZmonai.data.meta_tensorrupdaterrrrrrrrr) rrrrdata collate_fnretrZdata_for_batchreZre_str_rZrr`r<sP    r< batch_dataMapping | Iterabledetachpadc sttrfddD}nttr#fddD}n tddtddg}}t|tr>|nt|D]-\}}t|tr]t|ttfs]t|t j rc|j dkrc| |qBt|t rot|t|}qB|||fS) a Utility function based on `decollate_batch`, to identify the largest batch size from the collated data. returns batch_size, the list of non-iterable items, and the dictionary or list with their items decollated. See `decollate_batch` for more details. c s"i|] }|t|dqS)r$ fill_valuer3)r\rr!r#r&r$rZr`r  rz&_non_zipping_check..csg|] }t|dqSr%r'r)r#r&r$rZr`r rz&_non_zipping_check..Unable to de-collate: , type: rr)rrrrritemsrrrrrrrr rr) r!r#r$r&Z_deco batch_size non_iterablerrrZr(r`_non_zipping_checks   ".   r.c s|dur|St|ttttfst|jdkrt|ts|St|tj r|r)| }|j dkr6|r4| S|Stj |dd}t|trpt|t|jD]\}}t|trY||_d|_qJt||jD]\}}t|tro||_d|_q`|dj dkr|rdd|DSt|St||||\}}|dkrS|r|D]fddt|D<qttr|rtd |int} fd d| D} | Sttr|rtd |int} d d| D} | Std |d t|d)aS De-collate a batch of data (for example, as produced by a `DataLoader`). Returns a list of structures with the original tensor's 0-th dimension sliced into elements using `torch.unbind`. Images originally stored as (B,C,H,W,[D]) will be returned as (C,H,W,[D]). Other information, such as metadata, may have been stored in a list (or a list inside nested dictionaries). In this case we return the element of the list corresponding to the batch idx. Return types aren't guaranteed to be the same as the original, since numpy arrays will have been converted to torch.Tensor, sequences may be converted to lists of tensors, mappings may be converted into dictionaries. For example: .. code-block:: python batch_data = { "image": torch.rand((2,1,10,10)), DictPostFix.meta("image"): {"scl_slope": torch.Tensor([0.0, 0.0])} } out = decollate_batch(batch_data) print(len(out)) >>> 2 print(out[0]) >>> {'image': tensor([[[4.3549e-01...43e-01]]]), DictPostFix.meta("image"): {'scl_slope': 0.0}} batch_data = [torch.rand((2,1,10,10)), torch.rand((2,3,5,5))] out = decollate_batch(batch_data) print(out[0]) >>> [tensor([[[4.3549e-01...43e-01]]], tensor([[[5.3435e-01...45e-01]]])] batch_data = torch.rand((2,1,10,10)) out = decollate_batch(batch_data) print(out[0]) >>> tensor([[[4.3549e-01...43e-01]]]) batch_data = { "image": [1, 2, 3], "meta": [4, 5], # undetermined batch size } out = decollate_batch(batch_data, pad=True, fill_value=0) print(out) >>> [{'image': 1, 'meta': 4}, {'image': 2, 'meta': 5}, {'image': 3, 'meta': 0}] out = decollate_batch(batch_data, pad=False) print(out) >>> [{'image': 1, 'meta': 4}, {'image': 2, 'meta': 5}] Args: batch: data to be de-collated. detach: whether to detach the tensors. Scalars tensors will be detached into number types instead of torch tensors. pad: when the items in a batch indicate different batch size, whether to pad all the sequences to the longest. If False, the batch size will be the length of the shortest sequence. fill_value: when `pad` is True, the `fillvalue` to use when padding, defaults to `None`. NrrrFcSrrZ)item)r\trZrZr`rirz#decollate_batch..csg|]}tqSrZr )r\r decorrZr`rqr fillvaluecsg|] }tt|qSrZ)rrlr\r0)r3rZr`rtrcSrrZ)rr5rZrZr`r{rr)r*r)rrrrrrrrrrr#rr0unbindrrlr3rrr rr.rrrvaluesr) rr#r$r&Zout_listr1mrr-Z_genrret_listrZr2r`r3sP8      " r3methodcKs$ddlm}|d||d||S)aS Function version of :py:class:`monai.transforms.croppad.batch.PadListDataCollate`. Same as MONAI's ``list_data_collate``, except any tensors are centrally padded to match the shape of the biggest tensor in each dimension. This transform is useful if some of the applied transforms generate batch data of different sizes. This can be used on both list and dictionary data. Note that in the case of the dictionary data, this decollate function may add the transform information of `PadListDataCollate` to the list of invertible transforms if input batch have different spatial shape, so need to call static method: `monai.transforms.croppad.batch.PadListDataCollate.inverse` before inverting other transforms. Args: batch: batch of data to pad-collate method: padding method (see :py:class:`monai.transforms.SpatialPad`) mode: padding mode (see :py:class:`monai.transforms.SpatialPad`) kwargs: other arguments for the `np.pad` or `torch.pad` function. note that `np.pad` treats channel dimension as the first dimension. r)PadListDataCollate)r:rNrZ)Zmonai.transforms.croppad.batchr;)rr:rkwargsr;rZrZr`r?s r?cCs|S)z% No any collation operation. rZ)rrZrZr`r=sr= worker_idNonecCs tjj}t|j|jddS)z Callback function for PyTorch DataLoader `worker_init_fn`. It can set different random seed for the transforms in different workers. seedN)rutilsrget_worker_inforGdatasetr@)r= worker_inforZrZr`rJs rJr@cCst|ttfr|}|D]}t||d}q ||kr|S|dSt|ds%|St|dr6|j|td|dS|jD]}|drAq9t|j||d}q9|S)z Set seed or random state for all randomizable properties of obj. Args: obj: object to set seed or random state for. seed: set the random state with an integer seed. r?rY__dict__set_random_state__) rrkrrGhasattrrFrrE startswith)objr@_seedr0rrZrZr`rGs    rGaffinerrsuppress_zeroscCst|jdks|jd|jdkrtd|jdt|d|d|f||d^}}t|tjr>ttj||dd}n t t j||dd }|rRd ||dk<t|||d^}}|S) ap Computing the current spacing from the affine matrix. Args: affine: a d x d affine matrix. r: indexing based on the spatial rank, spacing is computed from `affine[:r, :r]`. dtype: data type of the output. suppress_zeros: whether to suppress the zeros with ones. Returns: an `r` dimensional vector of spacing. rrYz$affine must be a square matrix, got rN)dstdtyper/axisr) rr ValueErrorrrrrsqrtsumrh)rMrNrRrO_affiner spacingZspacing_rZrZr`r-s" "  r-cCsz|jddur |S|jdd}|dkr|St|jd|}t|j|d}t||r2|St|dr;t |S|S)z Check nifti object header's format, update the header if needed. In the updated image pixdim matches the affine. Args: img_nii: nifti image object rNrrN get_sform) headergetrhr get_zoomsr-rMallcloserHrC)img_niirpixdimZ norm_affinerZrZr`r1s  r1c Cs|jdd}t|jd|}||}}t||d}t||d}t|| }t|| }|jddkrL|sA|S|sL|||S|jddkrb|sW|S|sb| ||St|j |d} |j | |S)a Look at the sform and qform of the nifti object and correct it if any incompatibilities with pixel dimensions Adapted from https://github.com/NifTK/NiftyNet/blob/v0.6.0/niftynet/io/misc_io.py Args: img_nii: nifti image object rrNr[Z sform_codeZ qform_code) r]rhrr_r\Z get_qformr-r`Z set_sformZ set_qformrMZ set_zooms) rarrbZsformqformZ norm_sformZ norm_qformZsform_mismatchZqform_mismatchnormrZrZr`rCs,    rC np.ndarrayscalenp.ndarray | Sequence[float]diagonalc CsTtj|tdd}t|t|dkr#tdt|dt|ddtj|tdd}t|d}t||d}t||krIt||t|d }|d |}tt||}d ||dk<|rit t|d gS|d d d d f}tj |j |j }|tj |}tt |t|} tt|} |t | | d d d d f<| S) a# To make column norm of `affine` the same as `scale`. If diagonal is False, returns an affine that combines orthogonal rotation and the new scale. This is done by first decomposing `affine`, then setting the zoom factors to `scale`, and composing a new affine; the shearing factors are removed. If diagonal is True, returns a diagonal matrix, the scaling factors are set to the diagonal elements. This function always return an affine with zero translations. Args: affine (nxn matrix): a square matrix. scale: new scaling factor along each dimension. if the components of the `scale` are non-positive values, will use the corresponding components of the original pixdim, which is computed from the `affine`. diagonal: whether to return a diagonal scaling matrix. Defaults to True. Raises: ValueError: When ``affine`` is not a square matrix. ValueError: When ``scale`` contains a nonpositive scalar. Returns: the updated `n x n` affine. TrRcopyrzaffine must be n x n, got z x rrYr[Nr)rharrayrrrUr-rrr!diaglinalgcholeskyrinvsignabseye) rMrfrhZscale_nprrdZrzszsrotationrx new_affinerZrZr`rKs("     rK spatial_shapenp.ndarray | Sequence[int] in_affine out_affine scale_extenttuple[np.ndarray, np.ndarray]c s@tj|dtd}t|}tt||tjd}tt||tjd}fdd|D}ttj|ddi t|df} t | t | d d f} z tj ||| } Wntj jym} z td |d | d } ~ ww|| } | d d} | d d| d} rttj| d d n ttj| d d d} d }t| jd D]&}t| | d d ||d fd }tj|dtdr| d d|f}nq|d ur|d dd df|d|d ddf|d dd df| d}rtd|| dd}t|||dd dt|}| jtdd|fS)a Given input and output affine, compute appropriate shapes in the output space based on the input array's shape. This function also returns the offset to put the shape in a good position with respect to the world coordinate system. Args: spatial_shape: input array's shape in_affine (matrix): 2D affine matrix out_affine (matrix): 2D affine matrix scale_extent: whether the scale is computed based on the spacing or the full extent of voxels, for example, for a factor of 0.5 scaling: option 1, "o" represents a voxel, scaling the distance between voxels:: o--o--o o-----o option 2, each voxel has a physical extent, scaling the full voxel extent:: | voxel 1 | voxel 2 | voxel 3 | voxel 4 | | voxel 1 | voxel 2 | Option 1 may reduce the number of locations that requiring interpolation. Option 2 is more resolution agnostic, that is, resampling coordinates depend on the scaling factor, not on the number of voxels. Default is False, using option 1 to compute the shape and offset. T)rjrRrcs(g|]}r d|dfnd|dfqS)g?rnrrZ)r\rr{rZr`rw(z(compute_shape_offset..rrrkNrYzAffine z is not invertiblerSrrn)rtol@r}F)rj)rhrlrrrrIrrrreshape concatenate ones_likernsolve LinAlgErrorrUrjrptprrrr`r+rrrrqastyper)rwryrzr{rsrZ in_affine_Z out_affine_Z in_coordscornersZ corners_outrZall_dist out_shapeoffsetrrmZ in_offsetrZr~r`r/Qs<"$0$H(r/np.ndarray | intc Cs"t|tj}t|tj|ddd}|}|jdkr#td|jdtj||dd}|jdkrRt| tj }t |rA|dkrItd|dtj |d |d }t tt|d t|d d }|d |d |f|d |d |f<|d kr|d |d f|d |d f<t|||d ^}}|S) aP Using elements from affine, to create a new affine matrix by assigning the rotation/zoom/scaling matrix and the translation vector. When ``r`` is an integer, output is an (r+1)x(r+1) matrix, where the top left kxk elements are copied from ``affine``, the last column of the output affine is copied from ``affine``'s last column. `k` is determined by `min(r, len(affine) - 1)`. When ``r`` is an affine matrix, the output has the same shape as ``r``, and the top left kxk elements are copied from ``affine``, the last column of the output affine is copied from ``affine``'s last column. `k` is determined by `min(len(r) - 1, len(affine) - 1)`. Args: r (int or matrix): number of spatial dimensions or an output affine to be filled. affine (matrix): 2D affine matrix dtype: data type of the output array. Raises: ValueError: When ``affine`` dimensions is not 2. ValueError: When ``r`` is nonpositive. Returns: an (r+1) x (r+1) matrix (tensor or ndarray depends on the input ``affine`` data type) T) output_typerR wrap_sequencerrPz#affine must have 2 dimensions, got rrizr must be positive, got rY)rRNrk)r#rhrrrjrrUrlrruintisfinitersrrrr) rNrMrRZ affine_nprvrroutputr rZrZr`rIs"    $rI data_shape init_affine target_affine"tuple[np.ndarray, NdarrayOrTensor]c Cst|tj^}}t|tj^}}tj|}tj|}z tj||}Wnty=} z td|d|d| d} ~ ww|tj||} t | |^} }|| fS)ac Given the input ``init_affine``, compute the orientation transform between it and ``target_affine`` by rearranging/flipping the axes. Returns the orientation transform and the updated affine (tensor or ndarray depends on the input ``affine`` data type). Note that this function requires external module ``nibabel.orientations``. zThe input affine z and target affine z are not compatible.N) rrhrnibZ orientationsZio_orientationornt_transformrUZ inv_ornt_affr) rrrZ init_affine_r Ztarget_affine_Z start_orntZ target_orntrrrvrZrZr`rDs   rDrpostfixinput_file_namer folder_path data_root_dirseparate_foldermakedirsc Cstj|\}}tj|\}} | dkrtj|\}} d} |r)|r)tj||} tj|| } |r9tj| |} |rBtj| ddtj| |dkrP|d|n|} |dur^| d|7} tj| S)a Utility function to create the path to the output file based on the input filename (file name extension is not added by this function). When ``data_root_dir`` is not specified, the output file name is: `folder_path/input_file_name (no ext.) /input_file_name (no ext.)[_postfix][_patch_index]` otherwise the relative path with respect to ``data_root_dir`` will be inserted, for example: .. code-block:: python from monai.data import create_file_basename create_file_basename( postfix="seg", input_file_name="/foo/bar/test1/image.png", folder_path="/output", data_root_dir="/foo/bar", separate_folder=True, makedirs=False) # output: /output/test1/image/image_seg Args: postfix: output name's postfix input_file_name: path to the input image file. folder_path: path for the output file data_root_dir: if not empty, it specifies the beginning parts of the input file's absolute path. This is used to compute `input_file_rel_path`, the relative path to the file from `data_root_dir` to preserve folder structure when saving in case there are files in different folders with the same file names. separate_folder: whether to save every file in a separate folder, for example: if input filename is `image.nii`, postfix is `seg` and folder_path is `output`, if `True`, save as: `output/image/image_seg.nii`, if `False`, save as `output/image_seg.nii`. default to `True`. patch_index: if not None, append the patch index to filename. makedirs: whether to create the folder if it does not exist. z.gzrT)exist_okr N)ospathsplitsplitextrelpathjoinrnormpath) rrrrr patch_indexrZfiledirfilenameextZfiledir_rel_pathrrZrZr`r2s ." r2g?cpuBlendMode | str sigma_scaledevicetorch.device | int | strrRtorch.dtype | str | None torch.Tensorc Cs8t|t}t|}|tjkrtj||tjd}ni|tjkrrt|t |}ddt ||D}t t |D];}tj ||d d||dddtj|d}t |dd||d}|d krn|d |d |n|}q5ntd |d tjdtjdtt|d} tj|tj| d|}|S)a9Get importance map for different weight modes. Args: patch_size: Size of the required importance map. This should be either H, W [,D]. mode: {``"constant"``, ``"gaussian"``} How to blend output of overlapping windows. Defaults to ``"constant"``. - ``"constant``": gives equal weight to all predictions. - ``"gaussian``": gives less weight to predictions on edges of windows. sigma_scale: Sigma_scale to calculate sigma for each dimension (sigma = sigma_scale * dim_size). Used for gaussian mode only. device: Device to put importance map on. dtype: Data type of the output importance map. Raises: ValueError: When ``mode`` is not one of ["constant", "gaussian"]. Returns: Tensor of size patch_size. )rrRcSsg|]\}}||qSrZrZ)r\rZsigma_srZrZr`rErz*compute_importance_map..rYr)rendrRrrPrrkrczUnsupported mode: z, available options are [z, z].rQr)r%rrrCONSTANTonesrGAUSSIANrrrlrarangeexp unsqueezerUrrr0clamp_to) rTrrrrRZimportance_mapsigmasrrZ min_non_zerorZrZr`r."s(    ($r.rSequence[PathLike] | PathLikesuffixes Sequence[str]csJt|}|D]}dttjt|jtfdd|Dr"dSqdS)a Verify whether the specified file or files format match supported suffixes. If supported suffixes is None, skip the verification and return True. Args: filename: file name or a list of file names to read. if a list of files, verify all the suffixes. suffixes: all the supported image suffixes of current reader, must be a list of lower case suffixes. rc3s"|] }d|vVqdS)rN)lowerrZ full_suffixrZr`raergz&is_supported_format..FT)rrmaprrrrall)rr filenamesr)rZrr`r7Ws r7rratiosSequence[float] | Nonenum_partitions int | Noneshuffle drop_lasteven_divisiblecsrt}g}tt|} |rtj|} | | |rId} t|} |D]#} | }t|t | | |d|} | fdd| || Dq#|S|sOt d|sW|rWt d||krct d|d|ru||dkrut |||}nt ||}|r||n|}|s||dkr| | d ||7} n| d |} t|D]}| |||}| fd d|Dq|S) a> Split the dataset into N partitions. It can support shuffle based on specified random seed. Will return a set of datasets, every dataset contains 1 partition of original dataset. And it can split the dataset based on specified ratios or evenly split into `num_partitions`. Refer to: https://pytorch.org/docs/stable/distributed.html#module-torch.distributed.launch. Note: It also can be used to partition dataset for ranks in distributed training. For example, partition dataset before training and use `CacheDataset`, every rank trains with its own data. It can avoid duplicated caching content in each rank, but will not do global shuffle before every epoch: .. code-block:: python data_partition = partition_dataset( data=train_files, num_partitions=dist.get_world_size(), shuffle=True, even_divisible=True, )[dist.get_rank()] train_ds = SmartCacheDataset( data=data_partition, transform=train_transforms, replace_rate=0.2, cache_num=15, ) Args: data: input dataset to split, expect a list of data. ratios: a list of ratio number to split the dataset, like [8, 1, 1]. num_partitions: expected number of the partitions to evenly split, only works when `ratios` not specified. shuffle: whether to shuffle the original dataset before splitting. seed: random seed to shuffle the dataset, only works when `shuffle` is True. drop_last: only works when `even_divisible` is False and no ratios specified. if True, will drop the tail of the data to make it evenly divisible across partitions. if False, will add extra indices to make the data evenly divisible across partitions. even_divisible: if True, guarantee every partition has same length. Examples:: >>> data = [1, 2, 3, 4, 5] >>> partition_dataset(data, ratios=[0.6, 0.2, 0.2], shuffle=False) [[1, 2, 3], [4], [5]] >>> partition_dataset(data, num_partitions=2, shuffle=False) [[1, 3, 5], [2, 4]] >>> partition_dataset(data, num_partitions=2, shuffle=False, even_divisible=True, drop_last=True) [[1, 3], [2, 4]] >>> partition_dataset(data, num_partitions=2, shuffle=False, even_divisible=True, drop_last=False) [[1, 3, 5], [2, 4, 1]] >>> partition_dataset(data, num_partitions=2, shuffle=False, even_divisible=False, drop_last=False) [[1, 3, 5], [2, 4]] rr}cg|]}|qSrZrZrrrZr`rrz%partition_dataset..z,must specify number of partitions or ratios.z1drop_last only works when even_divisible is True.z)there is no enough data to be split into z partitions.NcrrZrZr\jrrZr`rr)rrrrhri RandomStaterrWrrrrUrrr)rrrrr@rrdata_lendatasetsindicesrsnext_idxZrsumrNr num_samples total_sizer_indicesrZrr`r@ks>>   "  r@classesc st|r t|tkrtd|dtdg}tt} t|D] \} } | | | q#g} t| D]"\} }t |||||||d}| sK|} q7t | |D]\}}||7}qPq7t j |}| D]}|rk|||fdd|Dqb|S)a_ Split the dataset into N partitions based on the given class labels. It can make sure the same ratio of classes in every partition. Others are same as :py:class:`monai.data.partition_dataset`. Args: data: input dataset to split, expect a list of data. classes: a list of labels to help split the data, the length must match the length of data. ratios: a list of ratio number to split the dataset, like [8, 1, 1]. num_partitions: expected number of the partitions to evenly split, only works when no `ratios`. shuffle: whether to shuffle the original dataset before splitting. seed: random seed to shuffle the dataset, only works when `shuffle` is True. drop_last: only works when `even_divisible` is False and no ratios specified. if True, will drop the tail of the data to make it evenly divisible across partitions. if False, will add extra indices to make the data evenly divisible across partitions. even_divisible: if True, guarantee every partition has same length. Examples:: >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] >>> classes = [2, 0, 2, 1, 3, 2, 2, 0, 2, 0, 3, 3, 1, 3] >>> partition_dataset_classes(data, classes, shuffle=False, ratios=[2, 1]) [[2, 8, 4, 1, 3, 6, 5, 11, 12], [10, 13, 7, 9, 14]] zlength of classes z must match the dataset length r)rrrrr@rrcrrZrZrrrZr`rrz-partition_dataset_classes..)r$rrUrrrrsortedr+r@rlrhrirr)rrrrrr@rrrZ class_indicesrcZclass_partition_indicesr Zper_class_indicesZper_class_partition_indicespartZ data_indicesrrrZrr`rAs8#    rAfactorr random_pickcCsft|\}}t}tt|D] }|tt|q|dkr1|t||d|g||dd|S)aY Utility function to resample the loaded datalist for training, for example: If factor < 1.0, randomly pick part of the datalist and set to Dataset, useful to quickly test the program. If factor > 1.0, repeat the datalist to enhance the Dataset. Args: data: original datalist to scale. factor: scale factor for the datalist, for example, factor=4.5, repeat the datalist 4 times and plus 50% of the original datalist. random_pick: whether to randomly pick data if scale factor has decimal part. seed: random seed to randomly pick data. gư>rY)rrrr@r)rmodfrrrextendr r@)rrrr@rfrepeatsrr rZrZr`rEs"rE partitionsSequence[Iterable]foldsrcsfddt|DS)a Select cross validation data based on data partitions and specified fold index. if a list of fold indices is provided, concatenate the partitions of these folds. Args: partitions: a sequence of datasets, each item is a iterable folds: the indices of the partitions to be combined. Returns: A list of combined datasets. Example:: >>> partitions = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] >>> select_cross_validation_folds(partitions, 2) [5, 6] >>> select_cross_validation_folds(partitions, [1, 2]) [3, 4, 5, 6] >>> select_cross_validation_folds(partitions, [-1, 2]) [9, 10, 5, 6] csg|] }|D]}|qqSrZrZ)r\Zfold_idZ data_itemrrZr`rLrz1select_cross_validation_folds..)r)rrrZrr`rF6srFrcCs\d}tjjdkrttj|ddd}ntjtj|ddddd}|S)z_ Args: item: data item to be hashed Returns: the corresponding hash key r T) sort_keyszutf-8Fusedforsecurity) sys version_infominorhashlibmd5jsondumpsencode hexdigest)r0 cache_keyrZrZr`r;Os   r;cCsXd}tjjdkrttjt||d}ntjtjt||ddd}| S)z Args: item: data item to be hashed protocol: protocol version used for pickling, defaults to `pickle.HIGHEST_PROTOCOL`. Returns: the corresponding hash key rr)protocolFr) rrrrrrPrrHrr)r0rrrZrZr`rBcs  rBcCs*t|ts|Sddt|||dDS)z/Return a new sorted dictionary from the `item`.cSs(i|]\}}|t|trt|n|qSrZ)rrrHr\rrrZrZr`r |rzsorted_dict..)rreverse)rrrr+)r0rrrZrZr`rHxs rH row_indicesSequence[int | str] | None col_namesSequence[str] | None col_types'dict[str, dict[str, Any] | None] | None col_groupsdict[str, Sequence[str]] | Nonelist[dict[str, Any]]c sJtfddt|}g}|dur|j}n*|D]'}t|ttfr;t|dkr,td| tt |d|dq| |q|durJ|j |n|j ||f} t|t rydd |D} | rg| j| d } d d |D} | ry| j| d d } | jdd} |duri|D]\} }|j ||fj| <qfddt| D} | S)a- Utility to join pandas tables, select rows, columns and generate groups. Will return a list of dictionaries, every dictionary maps to a row of data in tables. Args: dfs: data table in pandas Dataframe format. if providing a list of tables, will join them. row_indices: indices of the expected rows to load. it should be a list, every item can be a int number or a range `[start, end)` for the indices. for example: `row_indices=[[0, 100], 200, 201, 202, 300]`. if None, load all the rows in the file. col_names: names of the expected columns to load. if None, load all the columns. col_types: `type` and `default value` to convert the loaded columns, if None, use original data. it should be a dictionary, every item maps to an expected column, the `key` is the column name and the `value` is None or a dictionary to define the default value and data type. the supported keys in dictionary are: ["type", "default"], and note that the value of `default` should not be `None`. for example:: col_types = { "subject_id": {"type": str}, "label": {"type": int, "default": 0}, "ehr_0": {"type": float, "default": 0.0}, "ehr_1": {"type": float, "default": 0.0}, } col_groups: args to group the loaded columns to generate a new column, it should be a dictionary, every item maps to a group, the `key` will be the new column name, the `value` is the names of columns to combine. for example: `col_groups={"ehr": [f"ehr_{i}" for i in range(10)], "meta": ["meta_1", "meta_2"]}` kwargs: additional arguments for `pandas.merge()` API to join tables. cstj||fiSrc)pdmerge)lrN)r<rZr`rz)convert_tables_to_dicts..NrPz:range of row indices must contain 2 values: start and end.rrYcSs0i|]\}}|dur|ddur||dqS)Ndefault)r^rrZrZr`r s0z+convert_tables_to_dicts..)valuecSs*i|]\}}|durd|vr||dqS)NrrZrrZrZr`r s*Frirecords)orientcs2g|]\}t|fifddDqS)csi|] \}}||qSrZrZrrrZr`r rz6convert_tables_to_dicts...)rr+r)groupsrr`rs2z+convert_tables_to_dicts..)r rindextolistrrkrrrUrrrlocrr+fillnarto_dictr7r)dfsrrrrr<dfrowsrdata_defaultsrrr)colsrZ)rr<r`r0s2'       r0cCst|jddd}ddggdgdg}|t|dddg|d}t|tjr8tt|||St | |j |S)z Convert the ``affine`` between the `RAS` and `LPS` orientation by flipping the first two spatial dimensions. Args: affine: a 2D affine matrix. rrYrk)rkrkrY)rkrkrYrYrPrL) rrrrrrrmrrrhrrR)rMrZflip_dZ flip_diagrZrZr`r>s   r>r list[str]cCs|D]}||d}qdS)z Remove keys from a dictionary. Operates in-place so nothing is returned. Args: data: dictionary to be modified. keys: keys to be deleted from dictionary. Returns: `None` N)pop)rrrr rZrZr`rLs rLrcCst}t||ddS)z Remove extra metadata from the dictionary. Operates in-place so nothing is returned. Args: meta: dictionary containing metadata to be modified. Returns: `None` )rrN)rNrL)rrrZrZr`rMs rMc CsBddddddddd d d g d d tdDdd tdD}|S)z| Get a list of unnecessary keys for metadata that can be removed. Returns: List of keys to be removed. Zsrow_xZsrow_yZsrow_zZ quatern_bZ quatern_cZ quatern_dZ qoffset_xZ qoffset_yZ qoffset_zrrbcSg|]}d|dqS)zdim[]rZrrZrZr`r rz+get_extra_metadata_keys..cSr)zpixdim[rrZrrZrZr`r r)r)rrZrZr`rNs"  rNcCsLt|tjr tt|St|tr|dkSt|r"tt|S|duS)zPReturns whether `val` indicates "no_channel", for MetaKeys.ORIGINAL_CHANNEL_DIM.Z no_channelN)rrrruisnanrrhisscalar)valrZrZr`rOs   rOrc)rRrSrTrSrUrVrWrX)rZrnT) rorSrTrprqrSrrrsrtrurWrv)T) rorSrTrSr|rSr}rurWr~)rZrnF) rorSrTrrqrSrrrrtru)rrrTrprqrSrrrsrrurrrrrWr)rorSrTrrWr)rYr)rrrr)rr)r!r"r#rur$ru)TTN)r#ru)rrr:rrr)r=rrWr>)r@rrWr)rMrrNrrOrurWr)rMrerfrgrhru)F) rwrxryrrzrr{rurWr|)rNrrMrrWr)rrSrrrrrWr)rTNT)rrrrrrrrrrurrurWr) rTrrrrrsrrrRrrWr)rrrrrWru)NNFrFF)rrrrrrrrur@rrrurru)rrrrSrrrrrrur@rrrurru)Fr)rrrrrrur@r)rrrrprWr)rWr)NF)NNNN) rrrrrrrrrWr)rMrrWr)rrrrrWr>)rrrWr>)rWr)rWru)o __future__rrrrrrrPr collectionsrrcollections.abcrrrrr rjr functoolsr itertoolsr rrpathlibrtypingrrrhrrrmonai.config.type_definitionsrrrmonai.data.meta_objr monai.utilsrrrrrrrrrr r!r"r#r$r%r&rr r(r__all__r,r+r5r:r4r9WRAPr8r6rrrr<r.r3 SYMMETRICrr?r=rJrGrr-r1rCrKr/float64rIrDr2float32r.r7r@rArErFr;HIGHEST_PROTOCOLrBrHr0r>rLrMrNrOrZrZrZr`s       H  )  # . 2 V @  9 i   %8 ? / M 5 q D     M   "