o
    i                    @  s  d Z ddlmZ ddlmZmZmZ ddlmZ ddl	m
Z
 ddlZddlZddlmZmZmZmZmZmZmZmZmZmZmZ ddlmZ dd	lmZmZ dd
lm Z m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z'm(Z( ddl)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7 ddl8m9Z9m:Z: ddl;m<Z<m=Z=m>Z>m?Z?m@Z@ ddlAmBZBmCZC ddlDmEZEmFZF g dZGeBH ZIG dd de5e3ZJG dd de5e3ZKG dd de5e3ZLG dd de5e3ZMG dd deMZNG d d! d!e5e3ZOG d"d# d#e7e5e3ZPG d$d% d%e5e3ZQG d&d' d'e7e5e3ZRG d(d) d)e5ZSG d*d+ d+e5ZTG d,d- d-e5ZUG d.d/ d/e6e5ZVG d0d1 d1e5e3ZWG d2d3 d3e7e5e3ZXeK ZYZZeL Z[Z\eO Z]Z^eP Z_Z`eM ZaZbeQ ZcZdeR ZeZfeS ZgZheT ZiZjeU ZkZleV ZmZneW ZoZpeX ZqZreJ ZsZtdS )4z
A collection of dictionary-based wrappers around the "vanilla" transforms for box operations
defined in :py:class:`monai.apps.detection.transforms.array`.

Class names are ended with 'd' to denote dictionary-based transforms.
    )annotations)HashableMappingSequence)deepcopy)AnyN)	AffineBox	BoxToMaskClipBoxToImageConvertBoxModeConvertBoxToStandardModeFlipBox	MaskToBoxRotateBox90SpatialCropBoxStandardizeEmptyBoxZoomBox)convert_box_to_mask)KeysCollectionSequenceStr)	DtypeLikeNdarrayOrTensor)COMPUTE_DTYPEBoxModeclip_boxes_to_image)
MetaTensorget_track_meta)orientation_ras_lps)FlipRandFlipRandZoomRotate90SpatialCropZoom)InvertibleTransform)MapTransformRandomizableRandomizableTransform)#generate_pos_neg_label_crop_centersmap_binary_to_indices)InterpolateModeNumpyPadModeensure_tupleensure_tuple_repfall_back_tuple)PostFix	TraceKeys)convert_data_typeconvert_to_tensor)*StandardizeEmptyBoxdStandardizeEmptyBoxDStandardizeEmptyBoxDictConvertBoxModedConvertBoxModeDConvertBoxModeDictConvertBoxToStandardModedConvertBoxToStandardModeDConvertBoxToStandardModeDictAffineBoxToImageCoordinatedAffineBoxToImageCoordinateDAffineBoxToImageCoordinateDictZoomBoxdZoomBoxDZoomBoxDictRandZoomBoxdRandZoomBoxDRandZoomBoxDictFlipBoxdFlipBoxDFlipBoxDictRandFlipBoxdRandFlipBoxDRandFlipBoxDictClipBoxToImagedClipBoxToImageDClipBoxToImageDict
BoxToMaskd
BoxToMaskDBoxToMaskDict
MaskToBoxd
MaskToBoxDMaskToBoxDictRandCropBoxByPosNegLabeldRandCropBoxByPosNegLabelDRandCropBoxByPosNegLabelDictRotateBox90dRotateBox90DRotateBox90DictRandRotateBox90dRandRotateBox90DRandRotateBox90Dictc                      s8   e Zd ZdZdd fddZdddZdddZ  ZS )r3   a  
    Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.StandardizeEmptyBox`.

    When boxes are empty, this transform standardize it to shape of (0,4) or (0,6).

    Example:
        .. code-block:: python

            data = {"boxes": torch.ones(0,), "image": torch.ones(1, 128, 128, 128)}
            box_converter = StandardizeEmptyBoxd(box_keys=["boxes"], box_ref_image_keys="image")
            box_converter(data)
    Fbox_keysr   box_ref_image_keysstrallow_missing_keysboolreturnNonec                   s4   t  || t|}t|dkrtd|| _dS )ap  
        Args:
            box_keys: Keys to pick data for transformation.
            box_ref_image_keys: The single key that represents the reference image to which ``box_keys`` are attached.
            allow_missing_keys: don't raise exception if key is missing.

        See also :py:class:`monai.apps.detection,transforms.array.ConvertBoxToStandardMode`
           |Please provide a single key for box_ref_image_keys.                All boxes of box_keys are attached to box_ref_image_keys.N)super__init__r,   len
ValueErrorr^   )selfr]   r^   r`   box_ref_image_keys_tuple	__class__ l/home/dell461/cl/sdc2/last_ska_mid/HISourceFinder-master-l/src/monai/apps/detection/transforms/dictionary.pyrg   t   s   	
zStandardizeEmptyBoxd.__init__data"Mapping[Hashable, NdarrayOrTensor]dict[Hashable, NdarrayOrTensor]c                 C  sN   t |}t|| j jd }t|d| _| |D ]}| || ||< q|S )Nrd   )spatial_dims)dictrh   r^   shaper   	converterkey_iterator)rj   rp   drs   keyrn   rn   ro   __call__   s   zStandardizeEmptyBoxd.__call__c                 C  s   t |S Nrt   rj   rp   rn   rn   ro   inverse   s   zStandardizeEmptyBoxd.inverse)F)r]   r   r^   r_   r`   ra   rb   rc   rp   rq   rb   rr   __name__
__module____qualname____doc__rg   rz   r~   __classcell__rn   rn   rl   ro   r3   f   s
    
r3   c                      s>   e Zd ZdZ			dd fddZdddZdddZ  ZS )r6   a  
    Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.ConvertBoxMode`.

    This transform converts the boxes in src_mode to the dst_mode.

    Example:
        .. code-block:: python

            data = {"boxes": torch.ones(10,4)}
            # convert boxes with format [xmin, ymin, xmax, ymax] to [xcenter, ycenter, xsize, ysize].
            box_converter = ConvertBoxModed(box_keys=["boxes"], src_mode="xyxy", dst_mode="ccwh")
            box_converter(data)
    NFr]   r   src_mode$str | BoxMode | type[BoxMode] | Nonedst_moder`   ra   rb   rc   c                   s    t  || t||d| _dS )a  
        Args:
            box_keys: Keys to pick data for transformation.
            src_mode: source box mode. If it is not given, this func will assume it is ``StandardMode()``.
                It follows the same format with ``src_mode`` in :class:`~monai.apps.detection.transforms.array.ConvertBoxMode` .
            dst_mode: target box mode. If it is not given, this func will assume it is ``StandardMode()``.
                It follows the same format with ``src_mode`` in :class:`~monai.apps.detection.transforms.array.ConvertBoxMode` .
            allow_missing_keys: don't raise exception if key is missing.

        See also :py:class:`monai.apps.detection,transforms.array.ConvertBoxMode`
        r   r   N)rf   rg   r   rv   )rj   r]   r   r   r`   rl   rn   ro   rg      s   zConvertBoxModed.__init__rp   rq   rr   c                 C  sL   t |}| |D ]}| || ||< | j||| jj| jjdd q	|S )N)srcdst
extra_info)rt   rw   rv   push_transformr   r   rj   rp   rx   ry   rn   rn   ro   rz      s
    zConvertBoxModed.__call__c                 C  sn   t |}| |D ]+}| ||}|tj d |tj d }}t||d}||| ||< | || q	|S )Nr   r   r   rt   rw   get_most_recent_transformr0   
EXTRA_INFOr   pop_transform)rj   rp   rx   ry   trr   r   inverse_converterrn   rn   ro   r~      s   zConvertBoxModed.inverse)NNF)
r]   r   r   r   r   r   r`   ra   rb   rc   r   r   rn   rn   rl   ro   r6      s    
r6   c                      s<   e Zd ZdZ		dd fddZdddZdddZ  ZS )r9   aq  
    Dictionary-based wrapper of :py:class:`monai.apps.detection.transforms.array.ConvertBoxToStandardMode`.

    Convert given boxes to standard mode.
    Standard mode is "xyxy" or "xyzxyz",
    representing box format of [xmin, ymin, xmax, ymax] or [xmin, ymin, zmin, xmax, ymax, zmax].

    Example:
        .. code-block:: python

            data = {"boxes": torch.ones(10,6)}
            # convert boxes with format [xmin, xmax, ymin, ymax, zmin, zmax] to [xmin, ymin, zmin, xmax, ymax, zmax]
            box_converter = ConvertBoxToStandardModed(box_keys=["boxes"], mode="xxyyzz")
            box_converter(data)
    NFr]   r   moder   r`   ra   rb   rc   c                   s   t  || t|d| _dS )a  
        Args:
            box_keys: Keys to pick data for transformation.
            mode: source box mode. If it is not given, this func will assume it is ``StandardMode()``.
                It follows the same format with ``src_mode`` in :class:`~monai.apps.detection.transforms.array.ConvertBoxMode` .
            allow_missing_keys: don't raise exception if key is missing.

        See also :py:class:`monai.apps.detection,transforms.array.ConvertBoxToStandardMode`
        )r   N)rf   rg   r   rv   )rj   r]   r   r`   rl   rn   ro   rg      s   z"ConvertBoxToStandardModed.__init__rp   rq   rr   c                 C  sF   t |}| |D ]}| || ||< | j||d| jjid q	|S )Nr   r   )rt   rw   rv   r   r   r   rn   rn   ro   rz      s
   z"ConvertBoxToStandardModed.__call__c                 C  s^   t |}| |D ]#}| ||}|tj d }td |d}||| ||< | || q	|S )Nr   r   r   )rj   rp   rx   ry   r   Zoriginal_moder   rn   rn   ro   r~      s   z!ConvertBoxToStandardModed.inverseNF)r]   r   r   r   r`   ra   rb   rc   r   r   rn   rn   rl   ro   r9      s    
r9   c                      sJ   e Zd ZdZddedfd fddZdddZdddZdddZ  Z	S ) r<   a  
    Dictionary-based transform that converts box in world coordinate to image 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``.
    FNr]   r   r^   r_   r`   ra   image_meta_key
str | Noneimage_meta_key_postfixaffine_lps_to_rasrb   rc   c                   sV   t  || t|}t|dkrtd|| _|p | d| | _t | _|| _	d S )Nrd   re   _)
rf   rg   r,   rh   ri   r^   r   r   converter_to_image_coordinater   )rj   r]   r^   r`   r   r   r   rk   rl   rn   ro   rg     s   	
z$AffineBoxToImageCoordinated.__init__rp   Mapping[Hashable, torch.Tensor]$tuple[NdarrayOrTensor, torch.Tensor]c           	      C  s   t |}| j}t|| j tr|| j j}n||v r|| }nt| dd|vr2td| d|d }| jr=t|}t	|t
j^}}t
|t}||fS )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.)rt   r   
isinstancer^   r   metari   r   r   r1   torchTensorr~   tor   )	rj   rp   rx   meta_key	meta_dictr   affine_tr   inv_affine_trn   rn   ro   extract_affine-  s"   

z*AffineBoxToImageCoordinated.extract_affinerq   rr   c                 C  sT   t |}| |\}}| |D ]}| j|| |d||< | j||d|id q|S Nr   r   r   )rt   r   rw   r   r   rj   rp   rx   r   r   ry   rn   rn   ro   rz   I     z$AffineBoxToImageCoordinated.__call__c                 C  sV   t |}| |D ]}| ||}|d d }t || |d||< | || q	|S )Nr   r   r   )rt   rw   r   r   r   )rj   rp   rx   ry   	transformr   rn   rn   ro   r~   S  s   z#AffineBoxToImageCoordinated.inverser]   r   r^   r_   r`   ra   r   r   r   r   r   ra   rb   rc   )rp   r   rb   r   r   )
r   r   r   r   DEFAULT_POST_FIXrg   r   rz   r~   r   rn   rn   rl   ro   r<     s    


r<   c                      s6   e Zd ZdZddedfd fddZdddZ  ZS )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``.
    FNr]   r   r^   r_   r`   ra   r   r   r   r   rb   rc   c                   s"   t  |||||| t | _d S r{   )rf   rg   r   converter_to_world_coordinate)rj   r]   r^   r`   r   r   r   rl   rn   ro   rg   t  s   	z$AffineBoxToWorldCoordinated.__init__rp   rq   rr   c                 C  sT   t |}| |\}}| |D ]}| j|| |d||< | j||d|id q|S r   )rt   r   rw   r   r   r   rn   rn   ro   rz     r   z$AffineBoxToWorldCoordinated.__call__r   r   )r   r   r   r   r   rg   rz   r   rn   rn   rl   ro   r   ]  s    r   c                      sF   e Zd ZdZejejdddfd  fddZd!ddZ	d!ddZ
  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.
    NTF
image_keysr   r]   r^   zoomSequence[float] | floatr   r   padding_modealign_corners#Sequence[bool | None] | bool | None	keep_sizera   r`   kwargsr   rb   rc   c
                   s   t || _t || _t | j| j |	 t|t| j| _t|t| j| _t|t| j| _	t|t| j| _
td||d|
| _|| _d S )Nr   r   rn   )r,   r   r]   rf   rg   r-   rh   r^   r   r   r   r#   zoomerr   )rj   r   r]   r^   r   r   r   r   r   r`   r   rl   rn   ro   rg     s   


zZoomBoxd.__init__rp   r   dict[Hashable, torch.Tensor]c                 C  s   t |}t| j| jD ]D\}}|| jdd  }dd t| jj|D }dd t||D | j_t| jj| jd|| |d||< | j	||| jj|ddd	 qt| j
| j| j| jD ]\}}}	}
| j|| ||	|
d
||< q[|S )Nrd   c                 S      g | ]\}}t t|| qS rn   intround.0zssrn   rn   ro   
<listcomp>       z%ZoomBoxd.__call__.<locals>.<listcomp>c                 S     g | ]
\}}|t | qS rn   floatr   r   dsrn   rn   ro   r         r   src_spatial_sizebox_keyr   r   typer   )r   r   r   )rt   zipr]   r^   ru   r   r   r   r   r   r   r   r   r   )rj   rp   rx   r   box_ref_image_keyr   dst_spatial_sizery   r   r   r   rn   rn   ro   rz     s$   
zZoomBoxd.__call__c           	      C  s   t |}| |D ]R}| j||dd}|tj dd}|dkr*| j|| ||< |dkr[t	|tj d }|tj d }t
d|  | jjd	}||| |d
||< | || q	|S )NFcheckr   	image_keyr   r   r   rd   r   r   )rt   rw   r   r0   r   getr   r~   nparrayr   tolistr   r   )	rj   rp   rx   ry   r   key_typer   r   box_inverse_transformrn   rn   ro   r~     s   zZoomBoxd.inverse)r   r   r]   r   r^   r   r   r   r   r   r   r   r   r   r   ra   r`   ra   r   r   rb   rc   rp   r   rb   r   )r   r   r   r   r*   AREAr+   EDGErg   rz   r~   r   rn   rn   rl   ro   r?     s    %
r?   c                      s^   e Zd ZdZejZdddejej	dddfd,ddZ
d-d. fd#d$Zd/d(d)Zd/d*d+Z  ZS )0rB   a  
    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?NTFr   r   r]   r^   probr   min_zoomr   max_zoomr   r   r   r   r   r   ra   r`   r   r   rb   rc   c                 K  s   t || _t || _t| | j| j | t| | t|t| j| _t	dd|||
d|| _
t|t| j| _t|t| j| _t|	t| j| _|
| _d S )N      ?)r   r   r   r   rn   )r,   r   r]   r%   rg   r'   r-   rh   r^   r    	rand_zoomr   r   r   r   )rj   r   r]   r^   r   r   r   r   r   r   r   r`   r   rn   rn   ro   rg     s   


zRandZoomBoxd.__init__seed
int | Nonestatenp.random.RandomState | Nonec                   s    t  || | j|| | S r{   )rf   set_random_stater   rj   r   r   rl   rn   ro   r   9  s   zRandZoomBoxd.set_random_staterp   r   r   c                 C  sl  t |}| |}|dkr|S | d  | j||  t| j| jD ]G\}}| jrj|| jdd  }dd t| jj	|D }dd t||D | j_	t
| jj	| jd|| |d||< | j||| jj	|dd	d
 q#t| j| j| j| jD ]=\}}	}
}| jr| j|| |	|
|dd||< nt|| t d||< t r| jr| j|| ddni }| j|| |d
 qv|S )Nrn   rd   c                 S  r   rn   r   r   rn   rn   ro   r   M  r   z)RandZoomBoxd.__call__.<locals>.<listcomp>c                 S  r   rn   r   r   rn   rn   ro   r   N  r   r   r   r   r   r   F)r   r   r   	randomize
track_metar   )rt   	first_keyr   r   r   r]   r^   _do_transformru   _zoomr   r   r   r   r   r   r   r2   r   r   )rj   rp   rx   r   r   r   r   r   ry   r   r   r   xformrn   rn   ro   rz   >  sB   


zRandZoomBoxd.__call__c           
      C  s   t |}| |D ]i}| j||dd}|tj dd}|tj rr|dkrA| || }|| j	|tj  | j
|| ||< |dkrrt|tj d }|tj d }td|  | j
jd	}	|	|| |d
||< | || q	|S )NFr   r   r   r   r   r   r   r   r   )rt   rw   r   r0   r   r   DO_TRANSFORMr   applied_operationsappendr   r~   r   r   r   r   r   )
rj   rp   rx   ry   r   r   r   r   r   r   rn   rn   ro   r~   i  s"   
zRandZoomBoxd.inverse)r   r   r]   r   r^   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ra   r`   ra   r   r   rb   rc   NN)r   r   r   r   rb   rB   r   )r   r   r   r   r    backendr*   r   r+   r   rg   r   rz   r~   r   rn   rn   rl   ro   rB     s    '
+rB   c                      sB   e Zd ZdZejZ		dd fddZdddZdddZ  Z	S )rE   a  
    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.
    NFr   r   r]   r^   spatial_axisSequence[int] | int | Noner`   ra   rb   rc   c                   s\   t || _t || _t | j| j | t|t| j| _t|d| _	t
| j	jd| _d S N)r   )r,   r   r]   rf   rg   r-   rh   r^   r   flipperr   r   box_flipper)rj   r   r]   r^   r   r`   rl   rn   ro   rg     s   

zFlipBoxd.__init__rp   r   r   c                 C  s~   t |}| jD ]}| || ||< qt| j| jD ]"\}}|| jdd  }| || |||< | j|||ddd q|S )Nrd   r   spatial_sizer   r   )	rt   r   r   r   r]   r^   ru   r   r   )rj   rp   rx   ry   r   r   r  rn   rn   ro   rz     s   
zFlipBoxd.__call__c                 C  s   t |}| |D ]>}| j||dd}|tji dd}|dkr,| j|| ||< |dkrG|tj d }| || |||< | 	|| q	|S NFr   r   r   r   r  )
rt   rw   r   r   r0   r   r   r~   r   r   rj   rp   rx   ry   r   r   r  rn   rn   ro   r~     s   zFlipBoxd.inverser   )r   r   r]   r   r^   r   r   r   r`   ra   rb   rc   r   )
r   r   r   r   r   r   rg   rz   r~   r   rn   rn   rl   ro   rE     s    
rE   c                      sP   e Zd ZdZejZ			d d!ddZd"d# fddZd$ddZd$ddZ	  Z
S )%rH   a@  
    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.
    r   NFr   r   r]   r^   r   r   r   r   r`   ra   rb   rc   c                 C  sd   t || _t || _t| | j| j | t| | t|t| j| _t	|d| _
t|d| _d S r   )r,   r   r]   r%   rg   r'   r-   rh   r^   r   r   r   r   )rj   r   r]   r^   r   r   r`   rn   rn   ro   rg     s   
	
zRandFlipBoxd.__init__r   r   r   r   c                   s   t  || | S r{   )rf   r   r   rl   rn   ro   r     s   zRandFlipBoxd.set_random_staterp   r   r   c                 C  s   t |}| d  | jD ]4}| jr| || ||< nt|| t d||< t r@| jr5| j|| ddni }| j|| |d qt	| j
| jD ]%\}}|| jdd  }| jrb| || |||< | j|||ddd qH|S )Nr   Fr   r   rd   r   r   )rt   r   r   r   r   r2   r   r   r   r   r]   r^   ru   r   )rj   rp   rx   ry   
xform_infor   r   r  rn   rn   ro   rz     s    

zRandFlipBoxd.__call__c              	   C  s   t |}| |D ]X}| j||dd}|tj dd}|tj rY|dkrD| jd | || ||< W d    n1 s?w   Y  |dkrY|tj d }| 	|| |||< | j
||dd q	|S r  )rt   rw   r   r0   r   r   r   r   trace_transformr   r   r  rn   rn   ro   r~     s   
zRandFlipBoxd.inverse)r   NF)r   r   r]   r   r^   r   r   r   r   r   r`   ra   rb   rc   r   )r   r   r   r   rb   rH   r   )r   r   r   r   r   r   rg   r   rz   r~   r   rn   rn   rl   ro   rH     s    
rH   c                      s2   e Zd ZdZ		dd fddZdddZ  ZS )rK   a  
    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
            )
    TFr]   r   
label_keysr^   remove_emptyra   r`   rb   rc   c                   st   t |}t|dkrtdt |}t|dkrtdt || _t || |d | _|d | _t|d| _	d S )Nrd   fPlease 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.r   r  )
r,   rh   ri   r  rf   rg   r]   r^   r
   clipper)rj   r]   r  r^   r  r`   box_keys_tuplerk   rl   rn   ro   rg   (  s   


zClipBoxToImaged.__init__rp   rq   rr   c                   sp   t |  | j jdd  } fdd| jD }|  | j ||\ | j< }t| j|D ]\}}| |< q- S )Nrd   c                      g | ]} | qS rn   rn   r   	label_keyrx   rn   ro   r   F      z,ClipBoxToImaged.__call__.<locals>.<listcomp>)rt   r^   ru   r  r
  r]   r   )rj   rp   r  labelsZclipped_labelsr  Zclipped_labels_irn   r  ro   rz   C  s   
zClipBoxToImaged.__call__)TF)r]   r   r  r   r^   r   r  ra   r`   ra   rb   rc   r   r   r   r   r   rg   rz   r   rn   rn   rl   ro   rK     s    rK   c                      s2   e Zd ZdZ		dd fddZdddZ  ZS )rN   a  
    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"]),
                ]
            )

    Fr]   r   box_mask_keysr  r^   min_fg_labelr   ellipse_maskra   r`   rb   rc   c                   s   t  || t|| _t|| _t|| _t| jt| j  kr,t| jks1td tdt|t| j| _	|d | _
t| j
|d| _d S )NDPlease make sure len(label_keys)==len(box_keys)==len(box_mask_keys)!rd   bg_labelr  )rf   rg   r,   r]   r  r  rh   ri   r-   r^   r  r	   rv   )rj   r]   r  r  r^   r  r  r`   rl   rn   ro   rg     s   



$
zBoxToMaskd.__init__rp   rq   rr   c                 C  sn   t |}t| j| j| j| jD ]%\}}}}|| jdd  }| || || |||< ||  | j8  < q|S Nrd   )	rt   r   r]   r  r  r^   ru   rv   r  )rj   rp   rx   r   r  box_mask_keyr   r  rn   rn   ro   rz     s   zBoxToMaskd.__call__)FF)r]   r   r  r   r  r   r^   r   r  r   r  ra   r`   ra   rb   rc   r   r  rn   rn   rl   ro   rN   N  s    ?rN   c                      s8   e Zd ZdZejejdfd fddZdddZ  Z	S )rQ   a	  
    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"]),
                ]
            )
    Fr]   r   r  r  r  r   	box_dtypeDtypeLike | torch.dtypelabel_dtyper`   ra   rb   rc   c                   s   t  || t|| _t|| _t|| _t| jt| j  kr,t| jks1td td|d | _t	| j||d| _
|| _d S )Nr  rd   )r  r  r  )rf   rg   r,   r]   r  r  rh   ri   r  r   rv   r  )rj   r]   r  r  r  r  r  r`   rl   rn   ro   rg     s   



$

zMaskToBoxd.__init__rp   rq   rr   c                 C  sV   t |}t| j| j| jD ]\}}}||  | j7  < | || \||< ||< q|S r{   )rt   r   r]   r  r  r  rv   )rj   rp   rx   r   r  r  rn   rn   ro   rz     s
   zMaskToBoxd.__call__)r]   r   r  r   r  r   r  r   r  r  r  r  r`   ra   rb   rc   r   )
r   r   r   r   r   float32longrg   rz   r   rn   rn   rl   ro   rQ     s    6rQ   c                   @  sZ   e Zd ZdZdddddddddeddfd6d"d#Zd7d)d*Z			d8d9d/d0Zd:d4d5ZdS );rT   a  
    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.
    r   rd   TNg        Fr   r   r]   r_   r  r  Sequence[int] | intposr   negnum_samplesr   	whole_boxra   thresh_image_keyr   image_thresholdfg_indices_keybg_indices_key	meta_keysKeysCollection | Nonemeta_key_postfixallow_smallerr`   rb   rc   c                 C  sJ  t || _t| jdk rtdt| | j| t |}t|dkr&td|d | _t || _|| _|dk s;|dk rFtd| d| d|| dkrPtd|||  | _	|dk rctd	| d|| _
|| _|	| _|
| _|| _|| _|d u rtd t| jnt || _t| jt| jkrtd
t|t| j| _d | _|| _d S )Nrd   z+At least one image_keys should be provided.r  r   z)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,   r   rh   ri   r%   rg   r]   r  spatial_size_	pos_ratior#  r$  r%  r&  r'  r(  r-   r)  r+  centersr,  )rj   r   r]   r  r  r!  r"  r#  r$  r%  r&  r'  r(  r)  r+  r,  r`   r  rn   rn   ro   rg   +  s>   


"
z"RandCropBoxByPosNegLabeld.__init__boxesr   
image_sizeSequence[int]
np.ndarrayc           
      C  s  t |}t|tj^}}tj|td}t|d d d |f t}t|d d |d f t}t	|D ]}	| j
sm|d d |	f | j|	 d  d |d d |	f< |d d |	f | j|	 d  d |d d |	| f< q7|d d |	f | j|	 d  d |d d |	f< t|d d |	f |d d |	f |d d |	f< |d d |	f | j|	 d  |d d |	| f< t|d d |	| f |d d |	f |d d |	| f< q7t||dd\}}|S )N)dtype   rd   Tr	  )rh   r1   r   ndarray
zeros_liker   ceilastypefloorranger$  r  minimummaximumr   )
rj   r1  r2  rs   boxes_npr   Zextended_boxesZboxes_startZ
boxes_stopaxisrn   rn   ro   generate_fg_center_boxes_npe  s"     .4.0. z5RandCropBoxByPosNegLabeld.generate_fg_center_boxes_np
fg_indicesNdarrayOrTensor | None
bg_indicesthresh_imagec           
   	   C  s   |d u s|d u r5|  ||}t|t|jd |ddd}tj|ddddddf }t||| j\}}	n|}|}	t| j	| j
| j|||	| j| j| _d S )Nr   Fr  T)r@  keepdimsrd   .)rA  r   r   onesru   amaxr)   r&  r(   r  r#  r/  Rr,  r0  )
rj   r1  r2  rB  rD  rE  Zextended_boxes_npZmask_imgfg_indices_bg_indices_rn   rn   ro   r     s&   
z#RandCropBoxByPosNegLabeld.randomizerp   r   "list[dict[Hashable, torch.Tensor]]c                   s  t |  | jd  jdd  }t| j|| _ | j } fdd| jD }| jd ur2 	| jd nd }| j
d ur@ 	| j
d nd }| jrJ | j nd }| ||||| | jd u r^td fddt| jD }t| jD ]g\}	}
t ||	< tt|
| jd}dd |jD }d	d t|j|D }d
d t||D }t|d}| jD ]}| | ||	 |< qt|d}|||\||	 | j< }t| j|D ]
\}}|||	 |< qqo|S )Nr   rd   c                   r  rn   rn   r  r  rn   ro   r     r  z6RandCropBoxByPosNegLabeld.__call__.<locals>.<listcomp>z!no available ROI centers to crop.c                   s   g | ]}t  qS rn   r|   )r   r   r  rn   ro   r     r  )
roi_centerroi_sizec                 S  s   g | ]}t |jd qS )r   )maxstart)r   srn   rn   ro   r     s    c                 S  s   g | ]
\}}t |j|qS rn   )minstop)r   rQ  Zimage_size_arn   rn   ro   r     r   c                 S  s"   g | ]\}}t t|t|qS rn   )slicer   )r   rQ  ern   rn   ro   r     s   " )
roi_slices)rt   r   ru   r.   r.  r  r]   r  r'  popr(  r%  r   r0  ri   r<  r#  	enumerater   r"   tupleslicesr   r   )rj   rp   r2  r1  r  rB  rD  rE  resultsicentercropperZ
crop_startZcrop_endZcrop_slicesr   Z
boxcropperZcropped_labelsr  Zcropped_labels_irn   r  ro   rz     s6   




z"RandCropBoxByPosNegLabeld.__call__)"r   r   r]   r_   r  r   r  r   r!  r   r"  r   r#  r   r$  ra   r%  r   r&  r   r'  r   r(  r   r)  r*  r+  r_   r,  ra   r`   ra   rb   rc   )r1  r   r2  r3  rb   r4  )NNN)r1  r   r2  r3  rB  rC  rD  rC  rE  rC  rb   rc   )rp   r   rb   rL  )	r   r   r   r   r   rg   rA  r   rz   rn   rn   rn   ro   rT     s*    :
:!rT   c                      sD   e Zd ZdZejZ			dd fddZdddZdddZ  Z	S )rW   a  
    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.
    rd   r   rd   Fr   r   r]   r^   kr   spatial_axestuple[int, int]r`   ra   rb   rc   c                   sX   t || _t || _t | j| j | t|t| j| _t||| _	t
||| _d S r{   )r,   r   r]   rf   rg   r-   rh   r^   r!   img_rotatorr   box_rotator)rj   r   r]   r^   r`  ra  r`   rl   rn   ro   rg     s   
	
zRotateBox90d.__init__rp   r   c                 C  s   t |}t| j| jD ]I\}}t|| jdd  }| || |||< | jjd dkrI|| jj	d  || jj	d  || jj	d < || jj	d < | j
|||ddd q| jD ]}| || ||< qX|S )Nrd   r6  r   r   r   r   )rt   r   r]   r^   listru   rd  rc  r`  ra  r   r   )rj   rp   rx   ry   r   r  rn   rn   ro   rz     s   
zRotateBox90d.__call__r   c           	      C  s   t |}| |D ]H}| j||dd}|tj dd}d| jj }|dkr0| j|| ||< |dkrQ|tj d }t	|| j
j}||| |||< | || q	|S )NFr   r   r      r   r  )rt   rw   r   r0   r   r   rc  r`  r~   r   rd  ra  r   )	rj   rp   rx   ry   r   r   num_times_to_rotater  inverse_transformrn   rn   ro   r~     s   zRotateBox90d.inverse)rd   r_  F)r   r   r]   r   r^   r   r`  r   ra  rb  r`   ra   rb   rc   rp   r   rb   r   r   )
r   r   r   r   r   r   rg   rz   r~   r   rn   rn   rl   ro   rW     s    
rW   c                      sR   e Zd ZdZejZ				d!d"ddZd#ddZd$d% fddZd&dd Z	  Z
S )'rZ   an  
    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.
    r      r_  Fr   r   r]   r^   r   r   max_kr   ra  rb  r`   ra   rb   rc   c                 C  s^   t || _t || _t| | j| j | t| | || _|| _d| _t	|t
| j| _d S )Nr   )r,   r   r]   r%   rg   r'   rk  ra  _rand_kr-   rh   r^   )rj   r   r]   r^   r   rk  ra  r`   rn   rn   ro   rg   "  s   


zRandRotateBox90d.__init__rp   r   c           	      C  sP  |    t|}| jd dkr|S t| j| j}t| j| j}t| j| jD ]H\}}| j	rnt
|| jdd  }||| |||< | jd dkra|| jd  || jd  || jd < || jd < | j||| j|ddd q&| jD ]3}| j	r| j	r||| nt|| t d||< t r| j	r| j|| d	d
ni }| j|| |d qr|S )Nrf  r   rd   r6  r   )rand_kr  r   r   r   Fr   )r   rt   rl  r   ra  r!   r   r]   r^   r   re  ru   r   r   r2   r   r   )	rj   rp   rx   rd  rc  ry   r   r  r   rn   rn   ro   rz   7  s:   
zRandRotateBox90d.__call__N
Any | Nonec                   s$   | j | jd | _t d  d S r  )rI  randintrk  rl  rf   r   r}   rl   rn   ro   r   ]  s   zRandRotateBox90d.randomizer   c                 C  s   t |}| jd dkr|S | |D ]]}| j||dd}|tj dd}|tj ro|dkrD| j||dd}t	 
|| |tj ||< |dkro|tj d }d| }|tj d	 }	t|| j}
|
|| |	||< | || q|S )
Nrf  r   Fr   r   r   r   rm  r  )rt   rl  rw   r   r0   r   r   r   r   r!   rh  r   ra  )rj   rp   rx   ry   r   r   r   Znum_times_rotatedrg  r  rh  rn   rn   ro   r~   a  s&   
zRandRotateBox90d.inverse)r   rj  r_  F)r   r   r]   r   r^   r   r   r   rk  r   ra  rb  r`   ra   rb   rc   ri  r{   )rp   rn  rb   rc   r   )r   r   r   r   r   r   rg   rz   r   r~   r   rn   rn   rl   ro   rZ     s    
&rZ   )ur   
__future__r   collections.abcr   r   r   copyr   typingr   numpyr   r   Z%monai.apps.detection.transforms.arrayr   r	   r
   r   r   r   r   r   r   r   r   Z'monai.apps.detection.transforms.box_opsr   monai.configr   r   monai.config.type_definitionsr   r   monai.data.box_utilsr   r   r   monai.data.meta_tensorr   r   monai.data.utilsr   monai.transformsr   r   r    r!   r"   r#   monai.transforms.inverser$   monai.transforms.transformr%   r&   r'   monai.transforms.utilsr(   r)   monai.utilsr*   r+   r,   r-   r.   monai.utils.enumsr/   r0   monai.utils.type_conversionr1   r2   __all__r   r   r3   r6   r9   r<   r   r?   rB   rE   rH   rK   rN   rQ   rT   rW   rZ   r7   r8   r:   r;   r@   rA   rC   rD   r=   r>   rF   rG   rI   rJ   rL   rM   rO   rP   rR   rS   rU   rV   rX   rY   r[   r\   r4   r5   rn   rn   rn   ro   <module>   sl   
4 -,87\0g >P=ZN UDk