U Ph*@sHdZddlmZddlmZmZmZddlmZddl m Z ddl Z ddl Z ddlmZmZmZmZmZmZmZmZmZmZmZddlmZdd lmZmZdd lm Z m!Z!dd l"m#Z#m$Z$m%Z%dd l&m'Z'm(Z(dd l)m*Z*ddl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1ddl2m3Z3ddl4m5Z5m6Z6m7Z7ddl8m9Z9m:Z:ddl;mZ>m?Z?m@Z@ddlAmBZBmCZCddlDmEZEmFZFdddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dg*ZGeBHZIGd?dde5e3ZJGd@dde5e3ZKGdAdde5e3ZLGdBdde5e3ZMGdCdDdDeMZNGdEd!d!e5e3ZOGdFd$d$e7e5e3ZPGdGd'd'e5e3ZQGdHd*d*e7e5e3ZRGdId-d-e5ZSGdJd0d0e5ZTGdKd3d3e5ZUGdLd6d6e6e5ZVGdMd9d9e5e3ZWGdNd<d||}nt|dd|krdtd|d|d}|jrzt|}t |t j ^}}t | t}||fS)NzI is not found. Please check whether it is the correct the image meta key.affinez'affine' is not found in zL. Please check whether it is the correct the image meta key.)rur isinstancerarmetarirrr1torchTensorrtor) rjrsrymeta_key meta_dictraffine_tr inv_affine_trnrnroextract_affine-s"  z*AffineBoxToImageCoordinated.extract_affinerprqcCsTt|}||\}}||D].}|j|||d||<|j||d|idq |SNrrr)rurrxrrrjrsryrrrzrnrnror{Is z$AffineBoxToImageCoordinated.__call__cCsVt|}||D]>}|||}|dd}t|||d||<|||q|S)Nrrr)rurxrrr)rjrsryrz transformrrnrnrorSs  z#AffineBoxToImageCoordinated.inverse) rrrrDEFAULT_POST_FIXrgrr{rrrnrnrlror<s  c sLeZdZdZddedfdddddddd fd d Zd d dddZZS)AffineBoxToWorldCoordinateda Dictionary-based transform that converts box in image coordinate to world coordinate. Args: box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: The single key that represents the reference image to which ``box_keys`` are attached. remove_empty: whether to remove the boxes that are actually empty allow_missing_keys: don't raise exception if key is missing. image_meta_key: explicitly indicate the key of the corresponding metadata dictionary. for example, for data with key `image`, the metadata by default is in `image_meta_dict`. the metadata is a dictionary object which contains: filename, affine, original_shape, etc. it is a string, map to the `box_ref_image_key`. if None, will try to construct meta_keys by `box_ref_image_key_{meta_key_postfix}`. image_meta_key_postfix: if image_meta_keys=None, use `box_ref_image_key_{postfix}` to fetch the metadata according to the key data, default is `meta_dict`, the metadata is a dictionary object. For example, to handle key `image`, read/write affine matrices from the metadata `image_meta_dict` dictionary's `affine` field. affine_lps_to_ras: default ``False``. Yet if 1) the image is read by ITKReader, and 2) the ITKReader has affine_lps_to_ras=True, and 3) the box is in world coordinate, then set ``affine_lps_to_ras=True``. FNrr]r^rr_rcs"t||||||t|_dSr|)rfrgrconverter_to_world_coordinate)rjr`rarbrrrrlrnrorgts z$AffineBoxToWorldCoordinated.__init__rprqrrcCsTt|}||\}}||D].}|j|||d||<|j||d|idq |Sr)rurrxrrrrnrnror{s z$AffineBoxToWorldCoordinated.__call__)rrrrrrgr{rrnrnrlror]s rc sjeZdZdZejejdddfdddddddd d d d d fd d ZdddddZ dddddZ Z S)r?a Dictionary-based transform that zooms input boxes and images with the given zoom scale. Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. zoom: The zoom factor along the spatial axes. If a float, zoom is the same for each spatial axis. If a sequence, zoom should contain one value for each spatial axis. mode: {``"nearest"``, ``"nearest-exact"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html It also can be a sequence of string, each element corresponds to a key in ``keys``. padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html It also can be a sequence of bool or None, each element corresponds to a key in ``keys``. keep_size: Should keep original size (pad if needed), default is True. allow_missing_keys: don't raise exception if key is missing. kwargs: other arguments for the `np.pad` or `torch.pad` function. note that `np.pad` treats channel dimension as the first dimension. NTFrSequence[float] | floatr#Sequence[bool | None] | bool | Noner^rr_) image_keysr`razoomr padding_mode align_corners keep_sizerbkwargsrcc  st||_t||_t|j|j| t|t|j|_t|t|j|_t|t|j|_ t|t|j|_ t f||d| |_ ||_ dS)Nrr)r,rr`rfrgr-rhrarrrr#zoomerr) rjrr`rarrrrrrbrrlrnrorgs  zZoomBoxd.__init__rdict[Hashable, torch.Tensor]rrc Cst|}t|j|jD]\}}||jdd}ddt|jj|D}ddt||D|j_t|jj|jd|||d||<|j |||jj|ddd qt|j |j |j |j D]&\}}} } |j|||| | d ||<q|S) NrdcSs g|]\}}tt||qSrnintround.0zssrnrnro sz%ZoomBoxd.__call__..cSsg|]\}}|t|qSrnfloatrrdsrnrnrorsrsrc_spatial_sizebox_keyrrtyper)rrr)ruzipr`rarvrrrrrrrrr) rjrsryrbox_ref_image_keyrdst_spatial_sizerzrrrrnrnror{s, zZoomBoxd.__call__c Cst|}||D]}|j||dd}|tjdd}|dkrT|j||||<|dkrt |tjd}|tjd}t d| |jj d }||||d ||<| ||q|S) NFcheckr image_keyrrrrdrr)rurxrr0rgetrrnparrayrtolistrr) rjrsryrzrkey_typerrbox_inverse_transformrnrnrorszZoomBoxd.inverse) rrrrr*AREAr+EDGErgr{rrrnrnrlror?s%(cseZdZdZejZdddejej dddfdddd d d d d d d d ddd ddZ dddddfdd Z dddddZ dddddZ ZS) rBa Dictionary-based transform that randomly zooms input boxes and images with given probability within given zoom range. Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. prob: Probability of zooming. min_zoom: Min zoom factor. Can be float or sequence same size as image. If a float, select a random factor from `[min_zoom, max_zoom]` then apply to all spatial dims to keep the original spatial shape ratio. If a sequence, min_zoom should contain one value for each spatial axis. If 2 values provided for 3D data, use the first value for both H & W dims to keep the same zoom ratio. max_zoom: Max zoom factor. Can be float or sequence same size as image. If a float, select a random factor from `[min_zoom, max_zoom]` then apply to all spatial dims to keep the original spatial shape ratio. If a sequence, max_zoom should contain one value for each spatial axis. If 2 values provided for 3D data, use the first value for both H & W dims to keep the same zoom ratio. mode: {``"nearest"``, ``"nearest-exact"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html It also can be a sequence of string, each element corresponds to a key in ``keys``. padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html It also can be a sequence of bool or None, each element corresponds to a key in ``keys``. keep_size: Should keep original size (pad if needed), default is True. allow_missing_keys: don't raise exception if key is missing. kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html 皙?g?g?NTFrrrrrr^rr_) rr`raprobmin_zoommax_zoomrrrrrbrrcc Kst||_t||_t||j|j| t||t|t|j|_t fd||| d| |_ t|t|j|_ t|t|j|_ t| t|j|_ | |_dS)N?)rrrr)r,rr`r%rgr'r-rhrar rand_zoomrrrr) rjrr`rarrrrrrrrbrrnrnrorgs   zRandZoomBoxd.__init__ int | Nonenp.random.RandomState | Noneseedstaterccs t|||j|||Sr|)rfset_random_staterrjrrrlrnror9szRandZoomBoxd.set_random_staterrrrc Cspt|}||}|dkr|S|d|j||t|j|jD]\}}|jrF||jdd}ddt|jj |D}ddt||D|j_ t |jj |j d|||d||<|j |||jj |dd d qFt|j |j|j|jD]~\}} } } |jr|j||| | | d d ||<nt||td ||<tr|jrT|j||d dni} |j ||| d q|S)NrnrdcSs g|]\}}tt||qSrnrrrnrnrorMsz)RandZoomBoxd.__call__..cSsg|]\}}|t|qSrnrrrnrnrorNsrrrrrF)rrr randomize track_metar)ru first_keyrrrr`ra _do_transformrv_zoomrrrrrrrr2rr) rjrsryrrrrrrzrrrxformrnrnror{>sN    zRandZoomBoxd.__call__c Cst|}||D]}|j||dd}|tjdd}|tjr|dkr|||}||j |tj|j ||||<|dkrt |tjd}|tjd}td||j jd } | |||d ||<|||q|S) NFrrrrrrrrr)rurxrr0rr DO_TRANSFORMrapplied_operationsappendrrrrrrr) rjrsryrzrrrrrrrnrnroris  zRandZoomBoxd.inverse)NN)rrrrr backendr*rr+rrgrr{rrrnrnrlrorBs'(+csXeZdZdZejZddddddddfd d Zd d d ddZd d d ddZZ S)rEa Dictionary-based transform that flip boxes and images. Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. spatial_axis: Spatial axes along which to flip over. Default is None. allow_missing_keys: don't raise exception if key is missing. NFrSequence[int] | int | Noner^r_)rr`ra spatial_axisrbrccs\t||_t||_t|j|j|t|t|j|_t|d|_ t |j j d|_ dSN)r) r,rr`rfrgr-rhrarflipperr r box_flipper)rjrr`rarrbrlrnrorgs    zFlipBoxd.__init__rrrrcCs~t|}|jD]}|||||<qt|j|jD]D\}}||jdd}||||||<|j|||dddq4|S)Nrdr spatial_sizerr) rurrrr`rarvrr)rjrsryrzrrrrnrnror{s zFlipBoxd.__call__cCst|}||D]|}|j||dd}|tjidd}|dkrX|j||||<|dkr|tjd}||||||<| ||q|SNFrrrrr) rurxrrr0rrrrrrjrsryrzrrrrnrnrorszFlipBoxd.inverse)NF) rrrrrrrgr{rrrnrnrlrorEs  c sneZdZdZejZdddddddd d d d Zdd dddfdd ZdddddZdddddZ Z S)rHa@ Dictionary-based transform that randomly flip boxes and images with the given probabilities. Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. prob: Probability of flipping. spatial_axis: Spatial axes along which to flip over. Default is None. allow_missing_keys: don't raise exception if key is missing. rNFrrrr^r_)rr`rarrrbrccCsdt||_t||_t||j|j|t||t|t|j|_t |d|_ t |d|_ dSr) r,rr`r%rgr'r-rhrarrr r)rjrr`rarrrbrnrnrorgs    zRandFlipBoxd.__init__rrrcst|||Sr|)rfrrrlrnrorszRandFlipBoxd.set_random_staterrrrcCst|}|d|jD]h}|jr6|||||<nt||td||<tr|jrj|j||ddni}|j|||dqt |j |j D]J\}}||j dd}|jr| |||||<|j|||dddq|S)NrFrrrdrr)rurrrrr2rrrrr`rarvr)rjrsryrz xform_inforrrrnrnror{s  zRandFlipBoxd.__call__c Cst|}||D]}|j||dd}|tjdd}|tjr|dkrt|jd|||||<W5QRX|dkr|tjd}| |||||<|j ||ddq|Sr) rurxrr0rrrrtrace_transformrrrrnrnrors zRandFlipBoxd.inverse)rNF)NN) rrrrrrrgrr{rrrnrnrlrorHs csBeZdZdZddddddddfdd Zd d d d dZZS)rKa Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.ClipBoxToImage`. Clip the bounding boxes and the associated labels/scores to makes sure they are within the image. There might be multiple keys of labels/scores associated with one key of boxes. Args: box_keys: The single key to pick box data for transformation. The box mode is assumed to be ``StandardMode``. label_keys: Keys that represent the labels corresponding to the ``box_keys``. Multiple keys are allowed. box_ref_image_keys: The single key that represents the reference image to which ``box_keys`` and ``label_keys`` are attached. remove_empty: whether to remove the boxes that are actually empty allow_missing_keys: don't raise exception if key is missing. Example: .. code-block:: python ClipBoxToImaged( box_keys="boxes", box_ref_image_keys="image", label_keys=["labels", "scores"], remove_empty=True ) TFrr^r_)r` label_keysra remove_emptyrbrccstt|}t|dkrtdt|}t|dkr8tdt||_t|||d|_|d|_t|d|_ dS)NrdfPlease provide a single key for box_keys. All label_keys are attached to this box_keys.zPlease provide a single key for box_ref_image_keys. All box_keys and label_keys are attached to this box_ref_image_keys.rr) r,rhrirrfrgr`rar clipper)rjr`rrarrbbox_keys_tuplerkrlrnrorg(s     zClipBoxToImaged.__init__rprqrrcspt||jjdd}fdd|jD}||j||\|j<}t|j|D]\}}||<qZS)Nrdcsg|] }|qSrnrnr label_keyryrnrorFsz,ClipBoxToImaged.__call__..)rurarvrrr`r)rjrsrlabelsZclipped_labelsrZclipped_labels_irnrror{Cs zClipBoxToImaged.__call__)TFrrrrrgr{rrnrnrlrorKs c sFeZdZdZddddddddddfdd Zd d d d dZZS)rNa Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.BoxToMask`. Pairs with :py:class:`monai.apps.detection.transforms.dictionary.MaskToBoxd` . Please make sure the same ``min_fg_label`` is used when using the two transforms in pairs. The output ``d[box_mask_key]`` will have background intensity 0, since the following operations may pad 0 on the border. This is the general solution for transforms that need to be applied on images and boxes simultaneously. It is performed with the following steps. 1) use ``BoxToMaskd`` to covert boxes and labels to box_masks; 2) do transforms, e.g., rotation or cropping, on images and box_masks together; 3) use ``MaskToBoxd`` to convert box_masks back to boxes and labels. Args: box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_mask_keys: Keys to store output box mask results for transformation. Same length with ``box_keys``. label_keys: Keys that represent the labels corresponding to the ``box_keys``. Same length with ``box_keys``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. min_fg_label: min foreground box label. ellipse_mask: bool. - If True, it assumes the object shape is close to ellipse or ellipsoid. - If False, it assumes the object shape is close to rectangle or cube and well occupies the bounding box. - If the users are going to apply random rotation as data augmentation, we suggest setting ellipse_mask=True See also Kalra et al. "Towards Rotation Invariance in Object Detection", ICCV 2021. allow_missing_keys: don't raise exception if key is missing. Example: .. code-block:: python # This code snippet creates transforms (random rotation and cropping) on boxes, labels, and image together. import numpy as np from monai.transforms import Compose, RandRotated, RandSpatialCropd, DeleteItemsd transforms = Compose( [ BoxToMaskd( box_keys="boxes", label_keys="labels", box_mask_keys="box_mask", box_ref_image_keys="image", min_fg_label=0, ellipse_mask=True ), RandRotated(keys=["image","box_mask"],mode=["nearest","nearest"], prob=0.2,range_x=np.pi/6,range_y=np.pi/6,range_z=np.pi/6, keep_size=True,padding_mode="zeros" ), RandSpatialCropd(keys=["image","box_mask"],roi_size=128, random_size=False), MaskToBoxd( box_mask_keys="box_mask", box_keys="boxes", label_keys="labels", min_fg_label=0 ) DeleteItemsd(keys=["box_mask"]), ] ) Frrr^r_)r` box_mask_keysrra min_fg_label ellipse_maskrbrccst||t||_t||_t||_t|jt|jkrRt|jks\ntdt|t|j|_ |d|_ t |j |d|_ dS)NDPlease make sure len(label_keys)==len(box_keys)==len(box_mask_keys)!rdbg_labelr ) rfrgr,r`rr rhrir-rarr rw)rjr`r rrar r rbrlrnrorgs    ( zBoxToMaskd.__init__rprqrrcCsnt|}t|j|j|j|jD]J\}}}}||jdd}||||||||<|||j8<q|SNrd) rurr`rr rarvrwr)rjrsryrr box_mask_keyrrrnrnror{szBoxToMaskd.__call__)FFrrnrnrlrorNNs ?"c sPeZdZdZejejdfdddddddddfd d Zd d d ddZZ S)rQa Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.MaskToBox`. Pairs with :py:class:`monai.apps.detection.transforms.dictionary.BoxToMaskd` . Please make sure the same ``min_fg_label`` is used when using the two transforms in pairs. This is the general solution for transforms that need to be applied on images and boxes simultaneously. It is performed with the following steps. 1) use ``BoxToMaskd`` to covert boxes and labels to box_masks; 2) do transforms, e.g., rotation or cropping, on images and box_masks together; 3) use ``MaskToBoxd`` to convert box_masks back to boxes and labels. Args: box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_mask_keys: Keys to store output box mask results for transformation. Same length with ``box_keys``. label_keys: Keys that represent the labels corresponding to the ``box_keys``. Same length with ``box_keys``. min_fg_label: min foreground box label. box_dtype: output dtype for box_keys label_dtype: output dtype for label_keys allow_missing_keys: don't raise exception if key is missing. Example: .. code-block:: python # This code snippet creates transforms (random rotation and cropping) on boxes, labels, and images together. import numpy as np from monai.transforms import Compose, RandRotated, RandSpatialCropd, DeleteItemsd transforms = Compose( [ BoxToMaskd( box_keys="boxes", label_keys="labels", box_mask_keys="box_mask", box_ref_image_keys="image", min_fg_label=0, ellipse_mask=True ), RandRotated(keys=["image","box_mask"],mode=["nearest","nearest"], prob=0.2,range_x=np.pi/6,range_y=np.pi/6,range_z=np.pi/6, keep_size=True,padding_mode="zeros" ), RandSpatialCropd(keys=["image","box_mask"],roi_size=128, random_size=False), MaskToBoxd( box_mask_keys="box_mask", box_keys="boxes", label_keys="labels", min_fg_label=0 ) DeleteItemsd(keys=["box_mask"]), ] ) FrrzDtypeLike | torch.dtyper^r_)r`r rr  box_dtype label_dtyperbrccst||t||_t||_t||_t|jt|jkrRt|jks\ntd|d|_t |j||d|_ ||_ dS)Nr rd)rrr) rfrgr,r`rr rhrirrrwr)rjr`r rr rrrbrlrnrorgs    ( zMaskToBoxd.__init__rprqrrcCsVt|}t|j|j|jD]6\}}}|||j7<|||\||<||<q|Sr|)rurr`rr rrw)rjrsryrrrrnrnror{s zMaskToBoxd.__call__) rrrrrfloat32longrgr{rrnrnrlrorQs 6"c@seZdZdZdddddddddeddf dd dd d d d d dd dddd d d ddddZddddddZd#dddddddddZddd d!d"ZdS)$rTa Crop random fixed sized regions that contains foreground boxes. Suppose all the expected fields specified by `image_keys` have same shape, and add `patch_index` to the corresponding meta data. And will return a list of dictionaries for all the cropped images. If a dimension of the expected spatial size is bigger than the input image size, will not crop that dimension. So the cropped result may be smaller than the expected size, and the cropped results of several images may not have exactly the same shape. Args: image_keys: Keys to pick image data for transformation. They need to have the same spatial size. box_keys: The single key to pick box data for transformation. The box mode is assumed to be ``StandardMode``. label_keys: Keys that represent the labels corresponding to the ``box_keys``. Multiple keys are allowed. spatial_size: the spatial size of the crop region e.g. [224, 224, 128]. if a dimension of ROI size is bigger than image size, will not crop that dimension of the image. if its components have non-positive values, the corresponding size of `data[label_key]` will be used. for example: if the spatial size of input data is [40, 40, 40] and `spatial_size=[32, 64, -1]`, the spatial size of output data will be [32, 40, 40]. pos: used with `neg` together to calculate the ratio ``pos / (pos + neg)`` for the probability to pick a foreground voxel as a center rather than a background voxel. neg: used with `pos` together to calculate the ratio ``pos / (pos + neg)`` for the probability to pick a foreground voxel as a center rather than a background voxel. num_samples: number of samples (crop regions) to take in each list. whole_box: Bool, default True, whether we prefer to contain at least one whole box in the cropped foreground patch. Even if True, it is still possible to get partial box if there are multiple boxes in the image. thresh_image_key: if thresh_image_key is not None, use ``label == 0 & thresh_image > image_threshold`` to select the negative sample(background) center. so the crop center will only exist on valid image area. image_threshold: if enabled thresh_image_key, use ``thresh_image > image_threshold`` to determine the valid image content area. fg_indices_key: if provided pre-computed foreground indices of `label`, will ignore above `image_key` and `image_threshold`, and randomly select crop centers based on them, need to provide `fg_indices_key` and `bg_indices_key` together, expect to be 1 dim array of spatial indices after flattening. a typical usage is to call `FgBgToIndicesd` transform first and cache the results. bg_indices_key: if provided pre-computed background indices of `label`, will ignore above `image_key` and `image_threshold`, and randomly select crop centers based on them, need to provide `fg_indices_key` and `bg_indices_key` together, expect to be 1 dim array of spatial indices after flattening. a typical usage is to call `FgBgToIndicesd` transform first and cache the results. meta_keys: explicitly indicate the key of the corresponding metadata dictionary. used to add `patch_index` to the meta dict. for example, for data with key `image`, the metadata by default is in `image_meta_dict`. the metadata is a dictionary object which contains: filename, original_shape, etc. it can be a sequence of string, map to the `keys`. if None, will try to construct meta_keys by `key_{meta_key_postfix}`. meta_key_postfix: if meta_keys is None, use `key_{postfix}` to fetch the metadata according to the key data, default is `meta_dict`, the metadata is a dictionary object. used to add `patch_index` to the meta dict. 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). allow_missing_keys: don't raise exception if key is missing. rrdTNgFrr]zSequence[int] | intrrr^rzKeysCollection | Noner_)rr`rrposneg num_samples whole_boxthresh_image_keyimage_thresholdfg_indices_keybg_indices_key meta_keysmeta_key_postfix allow_smallerrbrccCsNt||_t|jdkr tdt||j|t|}t|dkrLtd|d|_t||_||_|dksv|dkrtd|d|d||dkrtd||||_ |dkrtd |d||_ ||_ | |_ | |_ | |_| |_| dkrtdt|jnt| |_t|jt|jkr,td t|t|j|_d|_||_dS) Nrdz+At least one image_keys should be provided.rrz)pos and neg must be nonnegative, got pos=z neg=.z%Incompatible values: pos=0 and neg=0.z6num_samples needs to be positive int, got num_samples=z.meta_keys should have the same length as keys.)r,rrhrir%rgr`r spatial_size_ pos_ratiorrrrrrr-rrcentersr)rjrr`rrrrrrrrrrrrrrbrrnrnrorg+s>     $z"RandCropBoxByPosNegLabeld.__init__rz Sequence[int]z np.ndarray)boxes image_sizercc Cst|}t|tj^}}tj|td}t|ddd|ft}t|dd|dft}t |D]0} |j s|dd| f|j | dd|dd| f<|dd| f|j | dd|dd| |f<qn|dd| f|j | dd|dd| f<t |dd| f|dd| f|dd| f<|dd| f|j | d|dd| |f<t |dd| |f|dd| f|dd| |f<qnt||dd\}}|S)N)dtyperdTr)rhr1rndarray zeros_likerceilastypefloorrangerrminimummaximumr) rjr$r%rtboxes_nprZextended_boxesZ boxes_startZ boxes_stopaxisrnrnrogenerate_fg_center_boxes_npes$  .4.0.z5RandCropBoxByPosNegLabeld.generate_fg_center_boxes_npzNdarrayOrTensor | None)r$r% fg_indices bg_indices thresh_imagercc Cs|dks|dkrj|||}t|t|jd|ddd}tj|ddddddf}t|||j\}} n|}|} t|j |j |j ||| |j |j |_dS)NrFr T)r1keepdimsrd.)r2rronesrvamaxr)rr(rrr"Rrr#) rjr$r%r3r4r5Zextended_boxes_npZmask_img fg_indices_ bg_indices_rnrnrors. z#RandCropBoxByPosNegLabeld.randomizerz"list[dict[Hashable, torch.Tensor]]rrcst||jdjdd}t|j||_|j}fdd|jD}|jdk rd |jdnd}|j dk r |j dnd}|j r|j nd}| ||||||j dkrtdfddt|jD}t|j D]\} } t|| <tt| |jd} dd| jD} d dt| j|D} d dt| | D}t|d } |jD]}| ||| |<qNt|d }|||\|| |j<}t|j|D]\}}||| |<qq|S) Nrrdcsg|] }|qSrnrnrrrnrorsz6RandCropBoxByPosNegLabeld.__call__..z!no available ROI centers to crop.csg|] }tqSrnr})rrrrnrors) roi_centerroi_sizecSsg|]}t|jdqS)r)maxstart)rsrnrnrorscSsg|]\}}t|j|qSrn)minstop)rr@Z image_size_arnrnrorscSs"g|]\}}tt|t|qSrn)slicer)rr@ernrnrors) roi_slices)rurrvr.r!rr`rrpoprrrr#rir-r enumeraterr"tupleslicesrr)rjrsr%r$rr3r4r5resultsicentercropperZ crop_startZcrop_endZ crop_slicesrZ boxcropperZcropped_labelsrZcropped_labels_irnrror{s4      z"RandCropBoxByPosNegLabeld.__call__)NNN) rrrrrrgr2rr{rnrnrnrorTs(:0:!c sZeZdZdZejZdddddddd d fd d Zd d dddZd ddddZZ S)rWa Input boxes and images are rotated by 90 degrees in the plane specified by ``spatial_axes`` for ``k`` times Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. k: number of times to rotate by 90 degrees. spatial_axes: 2 int numbers, defines the plane to rotate with 2 spatial axes. Default (0, 1), this is the first two axis in spatial dimensions. allow_missing_keys: don't raise exception if key is missing. rdrrdFrrtuple[int, int]r^r_)rr`rak spatial_axesrbrccsXt||_t||_t|j|j|t|t|j|_t|||_ t |||_ dSr|) r,rr`rfrgr-rhrar! img_rotatorr box_rotator)rjrr`rarPrQrbrlrnrorgs   zRotateBox90d.__init__rrrcCst|}t|j|jD]\}}t||jdd}||||||<|jjddkr||jj d||jj d||jj d<||jj d<|j |||dddq|j D]}|||||<q|S)Nrdr'rrrr) rurr`ralistrvrSrRrPrQrr)rjrsryrzrrrnrnror{s zRotateBox90d.__call__rc Cst|}||D]}|j||dd}|tjdd}d|jj}|dkr`|j||||<|dkr|tjd}t ||j j }||||||<| ||q|S)NFrrrrr) rurxrr0rrrRrPrrrSrQr) rjrsryrzrrnum_times_to_rotaterinverse_transformrnrnrors zRotateBox90d.inverse)rdrNF) rrrrrrrgr{rrrnrnrlrorWs c sneZdZdZejZddddddd d d d d dZdddddZddd dfdd ZdddddZ Z S)rZan With probability `prob`, input boxes and images are rotated by 90 degrees in the plane specified by `spatial_axes`. Args: image_keys: Keys to pick image data for transformation. box_keys: Keys to pick box data for transformation. The box mode is assumed to be ``StandardMode``. box_ref_image_keys: Keys that represent the reference images to which ``box_keys`` are attached. prob: probability of rotating. (Default 0.1, with 10% probability it returns a rotated array.) max_k: number of rotations will be sampled from `np.random.randint(max_k) + 1`. (Default 3) spatial_axes: 2 int numbers, defines the plane to rotate with 2 spatial axes. Default: (0, 1), this is the first two axis in spatial dimensions. allow_missing_keys: don't raise exception if key is missing. rrNFrrrrOr^r_)rr`rarmax_krQrbrccCs^t||_t||_t||j|j|t||||_||_d|_t |t |j|_ dS)Nr) r,rr`r%rgr'rYrQ_rand_kr-rhra)rjrr`rarrYrQrbrnrnrorg"s   zRandRotateBox90d.__init__rrrc CsT|t|}|jddkr"|St|j|j}t|j|j}t|j|jD]\}}|j rLt ||j dd}||||||<|jddkr||jd||jd||jd<||jd<|j |||j|dddqL|j D]j}|j r|j r|||nt||td||<tr|j r8|j||d d ni}|j |||dq|S) NrUrrdr'r)rand_krrrrFr)rrurZrrQr!rr`rarrTrvrrr2rr) rjrsryrSrRrzrrrrnrnror{7s:    zRandRotateBox90d.__call__Nz Any | Nonecs$|j|jd|_tddSr)r9randintrYrZrfrr~rlrnror]szRandRotateBox90d.randomizerc Cst|}|jddkr|S||D]}|j||dd}|tjdd}|tjr$|dkr|j||dd}t |||tj||<|dkr$|tjd}d|}|tjd } t ||j } | ||| ||<|||q$|S) NrUrFrrrrr[r) rurZrxrr0rrrrr!rWrrQ) rjrsryrzrrrZnum_times_rotatedrVrrWrnrnroras$  zRandRotateBox90d.inverse)rrXrNF)N) rrrrrrrgr{rrrrnrnrlrorZs&)ur __future__rcollections.abcrrrcopyrtypingrnumpyrrZ%monai.apps.detection.transforms.arrayrr r r r r rrrrrZ'monai.apps.detection.transforms.box_opsr monai.configrrmonai.config.type_definitionsrrZmonai.data.box_utilsrrrmonai.data.meta_tensorrrmonai.data.utilsrmonai.transformsrrr r!r"r#monai.transforms.inverser$monai.transforms.transformr%r&r'monai.transforms.utilsr(r) monai.utilsr*r+r,r-r.monai.utils.enumsr/r0monai.utils.type_conversionr1r2__all__rrr3r6r9r<rr?rBrErHrKrNrQrTrWrZr7r8r:r;r@rArCrDr=r>rFrGrIrJrLrMrOrPrRrSrUrVrXrYr[r\r4r5rnrnrnro s   4    -,87\0g>P=ZNUDk