U
    Ph_                     @  s  d Z ddlmZ ddlmZmZ ddlZddlZddl	m
Z
mZmZ ddlmZmZmZmZ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 dd
lm Z  ddl!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddddddddddddgZ*G dd deZ+G dd deZ,G dd deZ-G dd deZ.G dd deZ/G dd deZ0G dd deZ1G d d deZ2G d!d deZ3G d"d deZ4G d#d deZ5G d$d deZ6dS )%zr
A collection of "vanilla" transforms for box operations
https://github.com/Project-MONAI/MONAI/wiki/MONAI_Design
    )annotations)AnySequenceN)	DtypeLikeNdarrayOrTensorNdarrayTensor)BoxModeclip_boxes_to_imageconvert_box_modeconvert_box_to_standard_modeget_spatial_dimsspatial_crop_boxesstandardize_empty_box)Rotate90SpatialCrop)	Transform)ensure_tupleensure_tuple_repfall_back_tuplelook_up_option)TransformBackends   )apply_affine_to_boxesconvert_box_to_maskconvert_mask_to_box
flip_boxesresize_boxesrot90_boxesselect_labels
zoom_boxesStandardizeEmptyBoxConvertBoxToStandardModeConvertBoxMode	AffineBoxZoomBox	ResizeBoxFlipBoxClipBoxToImage	BoxToMask	MaskToBoxSpatialCropBoxRotateBox90c                   @  s<   e Zd ZdZejejgZdddddZdddd	d
Z	dS )r    z
    When boxes are empty, this transform standardize it to shape of (0,4) or (0,6).

    Args:
        spatial_dims: number of spatial dimensions of the bounding boxes.
    intNone)spatial_dimsreturnc                 C  s
   || _ d S Nr.   )selfr.    r3   Z/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/apps/detection/transforms/array.py__init__K   s    zStandardizeEmptyBox.__init__r   boxesr/   c                 C  s   t || jdS )zl
        Args:
            boxes: source bounding boxes, Nx4 or Nx6 or 0xM torch tensor or ndarray.
        r1   )r   r.   r2   r7   r3   r3   r4   __call__N   s    zStandardizeEmptyBox.__call__N
__name__
__module____qualname____doc__r   TORCHNUMPYbackendr5   r9   r3   r3   r3   r4   r    A   s   c                   @  s@   e Zd ZdZejejgZdddddddZddd	d
dZ	dS )r"   a
  
    This transform converts the boxes in src_mode to the dst_mode.

    Args:
        src_mode: source box mode. If it is not given, this func will assume it is ``StandardMode()``.
        dst_mode: target box mode. If it is not given, this func will assume it is ``StandardMode()``.

    Note:
        ``StandardMode`` = :class:`~monai.data.box_utils.CornerCornerModeTypeA`,
        also represented as "xyxy" for 2D and "xyzxyz" for 3D.

        src_mode and dst_mode can be:
            #. str: choose from :class:`~monai.utils.enums.BoxModeName`, for example,
                - "xyxy": boxes has format [xmin, ymin, xmax, ymax]
                - "xyzxyz": boxes has format [xmin, ymin, zmin, xmax, ymax, zmax]
                - "xxyy": boxes has format [xmin, xmax, ymin, ymax]
                - "xxyyzz": boxes has format [xmin, xmax, ymin, ymax, zmin, zmax]
                - "xyxyzz": boxes has format [xmin, ymin, xmax, ymax, zmin, zmax]
                - "xywh": boxes has format [xmin, ymin, xsize, ysize]
                - "xyzwhd": boxes has format [xmin, ymin, zmin, xsize, ysize, zsize]
                - "ccwh": boxes has format [xcenter, ycenter, xsize, ysize]
                - "cccwhd": boxes has format [xcenter, ycenter, zcenter, xsize, ysize, zsize]
            #. BoxMode class: choose from the subclasses of :class:`~monai.data.box_utils.BoxMode`, for example,
                - CornerCornerModeTypeA: equivalent to "xyxy" or "xyzxyz"
                - CornerCornerModeTypeB: equivalent to "xxyy" or "xxyyzz"
                - CornerCornerModeTypeC: equivalent to "xyxy" or "xyxyzz"
                - CornerSizeMode: equivalent to "xywh" or "xyzwhd"
                - CenterSizeMode: equivalent to "ccwh" or "cccwhd"
            #. BoxMode object: choose from the subclasses of :class:`~monai.data.box_utils.BoxMode`, for example,
                - CornerCornerModeTypeA(): equivalent to "xyxy" or "xyzxyz"
                - CornerCornerModeTypeB(): equivalent to "xxyy" or "xxyyzz"
                - CornerCornerModeTypeC(): equivalent to "xyxy" or "xyxyzz"
                - CornerSizeMode(): equivalent to "xywh" or "xyzwhd"
                - CenterSizeMode(): equivalent to "ccwh" or "cccwhd"
            #. None: will assume mode is ``StandardMode()``

    Example:
        .. code-block:: python

            boxes = torch.ones(10,4)
            # convert boxes with format [xmin, ymin, xmax, ymax] to [xcenter, ycenter, xsize, ysize].
            box_converter = ConvertBoxMode(src_mode="xyxy", dst_mode="ccwh")
            box_converter(boxes)
    N$str | BoxMode | type[BoxMode] | Noner-   )src_modedst_moder/   c                 C  s   || _ || _d S r0   rC   rD   )r2   rC   rD   r3   r3   r4   r5      s    zConvertBoxMode.__init__r   r6   c                 C  s   t || j| jdS )aS  
        Converts the boxes in src_mode to the dst_mode.

        Args:
            boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``

        Returns:
            bounding boxes with target mode, with same data type as ``boxes``, does not share memory with ``boxes``
        rE   )r
   rC   rD   r8   r3   r3   r4   r9      s    
zConvertBoxMode.__call__)NNr:   r3   r3   r3   r4   r"   V   s   -  c                   @  s>   e Zd ZdZejejgZddddddZddd	d
dZ	dS )r!   a  
    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].

    Args:
        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` .

    Example:
        .. code-block:: python

            boxes = torch.ones(10,6)
            # convert boxes with format [xmin, xmax, ymin, ymax, zmin, zmax] to [xmin, ymin, zmin, xmax, ymax, zmax]
            box_converter = ConvertBoxToStandardMode(mode="xxyyzz")
            box_converter(boxes)
    NrB   r-   )moder/   c                 C  s
   || _ d S r0   rF   )r2   rF   r3   r3   r4   r5      s    z!ConvertBoxToStandardMode.__init__r   r6   c                 C  s   t || jdS )a  
        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].

        Args:
            boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``

        Returns:
            bounding boxes with standard mode, with same data type as ``boxes``, does not share memory with ``boxes``
        rG   )r   rF   r8   r3   r3   r4   r9      s    z!ConvertBoxToStandardMode.__call__)Nr:   r3   r3   r3   r4   r!      s   c                   @  s.   e Zd ZdZejejgZddddddZdS )r#   z,
    Applies affine matrix to the boxes
    r   zNdarrayOrTensor | None)r7   affiner/   c                 C  s   |dkr|S t ||dS )z
        Args:
            boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            affine: affine matrix to be applied to the box coordinate
        N)rH   )r   )r2   r7   rH   r3   r3   r4   r9      s    zAffineBox.__call__N	r;   r<   r=   r>   r   r?   r@   rA   r9   r3   r3   r3   r4   r#      s   c                   @  sF   e Zd ZdZejejgZdddddddd	ZdddddddZ	d
S )r$   a  
    Zooms an ND Box with same padding or slicing setting with Zoom().

    Args:
        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.
        keep_size: Should keep original size (padding/slicing if needed), default is True.
        kwargs: other arguments for the `np.pad` or `torch.pad` function.
            note that `np.pad` treats channel dimension as the first dimension.
    FzSequence[float] | floatboolr   r-   )zoom	keep_sizekwargsr/   c                 K  s   || _ || _|| _d S r0   )rK   rL   rM   )r2   rK   rL   rM   r3   r3   r4   r5      s    zZoomBox.__init__Nr   Sequence[int] | int | Noner7   src_spatial_sizer/   c                 C  sr  t |d}t| j|| _| js*t|| jS |dkr:tdt||}dd t| j|D }tdd t||D | _t|| j}t	
t	|t	|sntt||D ]\}\}}|| }	t|	d }
|	d	kr|dd|f |
 |dd|f< |dd|| f |
 |dd|| f< q|	d	k r|dd|f |
 |dd|f< |dd|| f |
 |dd|| f< q|S )
z
        Args:
            boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            src_spatial_size: original image spatial size before zooming, used only when keep_size=True.
        r7   Nz2keep_size=True, src_spatial_size must be provided.c                 S  s    g | ]\}}t t|| qS r3   r,   round).0zssr3   r3   r4   
<listcomp>   s     z$ZoomBox.__call__.<locals>.<listcomp>c                 s  s   | ]\}}|t | V  qd S r0   )float)rT   rV   dsr3   r3   r4   	<genexpr>   s     z#ZoomBox.__call__.<locals>.<genexpr>   r   )r   r   rK   _zoomrL   r   
ValueErrorziptuplenpallclosearray	enumerateabs)r2   r7   rP   r.   Zdst_spatial_sizeZzoomed_boxesaxisodZzddiffhalfr3   r3   r4   r9      s*    


 * *zZoomBox.__call__)F)Nr:   r3   r3   r3   r4   r$      s   c                   @  sD   e Zd ZdZejejgZdddddddd	Zd
dd
dddZ	dS )r%   a  
    Resize the input boxes when the corresponding image is
    resized to given spatial size (with scaling, not cropping/padding).

    Args:
        spatial_size: expected shape of spatial dimensions after resize operation.
            if some components of the `spatial_size` are non-positive values, the transform will use the
            corresponding components of img size. For example, `spatial_size=(32, -1)` will be adapted
            to `(32, 64)` if the second spatial dimension size of img is `64`.
        size_mode: should be "all" or "longest", if "all", will use `spatial_size` for all the spatial dims,
            if "longest", rescale the image so that only the longest side is equal to specified `spatial_size`,
            which must be an int number in this case, keeping the aspect ratio of the initial image, refer to:
            https://albumentations.ai/docs/api_reference/augmentations/geometric/resize/
            #albumentations.augmentations.geometric.resize.LongestMaxSize.
        kwargs: other arguments for the `np.pad` or `torch.pad` function.
            note that `np.pad` treats channel dimension as the first dimension.
    allSequence[int] | intstrr   r-   )spatial_size	size_moderM   r/   c                 K  s   t |ddg| _|| _d S )Nri   longest)r   rm   rl   )r2   rl   rm   rM   r3   r3   r4   r5      s    zResizeBox.__init__r   rO   c                   s   t |d}t||}| jdkrXtt| j}||krJtd| d| dt| j|}n8t| jt	sltd| jt
|  t fdd|D }t|||S )	aU  
        Args:
            boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            src_spatial_size: original image spatial size before resizing.

        Raises:
            ValueError: When ``self.spatial_size`` length is less than ``boxes`` spatial dimensions.
        rQ   ri   zWlen(spatial_size) must be greater or equal to img spatial dimensions, got spatial_size=z img=.z=spatial_size must be an int number if size_mode is 'longest'.c                 3  s   | ]}t t|  V  qd S r0   rR   )rT   sscaler3   r4   rZ   =  s     z%ResizeBox.__call__.<locals>.<genexpr>)r   r   rm   lenr   rl   r]   r   
isinstancer,   maxr_   r   )r2   r7   rP   
input_ndimZsrc_spatial_size_output_ndimZspatial_size_r3   rq   r4   r9   $  s    	


zResizeBox.__call__N)ri   r:   r3   r3   r3   r4   r%     s   c                   @  s>   e Zd ZdZejejgZddddddZdd	d
ddZ	dS )r&   a  
    Reverses the box coordinates along the given spatial axis. Preserves shape.

    Args:
        spatial_axis: spatial axes along which to flip over. Default is None.
            The default `axis=None` will flip over all of the axes of the input array.
            If axis is negative it counts from the last to the first axis.
            If axis is a tuple of ints, flipping is performed on all of the axes
            specified in the tuple.

    NrN   r-   )spatial_axisr/   c                 C  s
   || _ d S r0   )rx   )r2   rx   r3   r3   r4   r5   Q  s    zFlipBox.__init__r   rj   )r7   rl   c                 C  s   t ||| jdS )z
        Args:
            boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            spatial_size: image spatial size.
        )rl   Z	flip_axes)r   rx   r2   r7   rl   r3   r3   r4   r9   T  s    zFlipBox.__call__)Nr:   r3   r3   r3   r4   r&   B  s   c                   @  sB   e Zd ZdZejejgZddddddZdd	d
ddddZ	dS )r'   a0  
    Clip the bounding boxes and the associated labels/scores to make sure they are within the image.
    There might be multiple arrays of labels/scores associated with one array of boxes.

    Args:
        remove_empty: whether to remove the boxes and corresponding labels that are actually empty
    FrJ   r-   )remove_emptyr/   c                 C  s
   || _ d S r0   )rz   )r2   rz   r3   r3   r4   r5   i  s    zClipBoxToImage.__init__r   +Sequence[NdarrayOrTensor] | NdarrayOrTensorrj   z/tuple[NdarrayOrTensor, tuple | NdarrayOrTensor]r7   labelsrl   r/   c                 C  s4   t |d}t||}t||| j\}}|t||fS )a  
        Args:
            boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            labels: Sequence of array. Each element represents classification labels or scores
                corresponding to ``boxes``, sized (N,).
            spatial_size: The spatial size of the image where the boxes are attached. len(spatial_size) should be in [2, 3].

        Returns:
            - clipped boxes, does not share memory with original boxes
            - clipped labels, does not share memory with original labels

        Example:
            .. code-block:: python

                box_clipper = ClipBoxToImage(remove_empty=True)
                boxes = torch.ones(2, 6)
                class_labels = torch.Tensor([0, 1])
                pred_scores = torch.Tensor([[0.4,0.3,0.3], [0.5,0.1,0.4]])
                labels = (class_labels, pred_scores)
                spatial_size = [32, 32, 32]
                boxes_clip, labels_clip_tuple = box_clipper(boxes, labels, spatial_size)
        rQ   )r   r   r	   rz   r   )r2   r7   r}   rl   r.   Z
boxes_clipkeepr3   r3   r4   r9   l  s    

zClipBoxToImage.__call__N)Fr:   r3   r3   r3   r4   r'   ^  s   c                   @  s@   e Zd ZdZejgZddddddd	Zd
d
dd
dddZdS )r(   a  
    Convert box to int16 mask image, which has the same size with the input image.

    Args:
        bg_label: background labels for the output mask image, make sure it is smaller than any foreground(fg) labels.
        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.
    Fr,   rJ   r-   )bg_labelellipse_maskr/   c                 C  s   || _ || _d S r0   )r   r   )r2   r   r   r3   r3   r4   r5     s    zBoxToMask.__init__r   rj   r|   c                 C  s   t |||| j| jS )a  
        Args:
            boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``.
            labels: classification foreground(fg) labels corresponding to `boxes`, dtype should be int, sized (N,).
            spatial_size: image spatial size.

        Return:
            - int16 array, sized (num_box, H, W). Each channel represents a box.
                The foreground region in channel c has intensity of labels[c].
                The background intensity is bg_label.
        )r   r   r   )r2   r7   r}   rl   r3   r3   r4   r9     s    zBoxToMask.__call__N)r   F)	r;   r<   r=   r>   r   r@   rA   r5   r9   r3   r3   r3   r4   r(     s   c                   @  sH   e Zd ZdZejgZdejej	fdddddddZ
d	d
dddZdS )r)   a  
    Convert int16 mask image to box, which has the same size with the input image.
    Pairs with :py:class:`monai.apps.detection.transforms.array.BoxToMask`.
    Please make sure the same ``min_fg_label`` is used when using the two transforms in pairs.

    Args:
        bg_label: background labels for the output mask image, make sure it is smaller than any foreground(fg) labels.
        box_dtype: output dtype for boxes
        label_dtype: output dtype for labels
    r   r,   zDtypeLike | torch.dtyper-   )r   	box_dtypelabel_dtyper/   c                 C  s   || _ || _|| _d S r0   )r   r   r   )r2   r   r   r   r3   r3   r4   r5     s    zMaskToBox.__init__r   z'tuple[NdarrayOrTensor, NdarrayOrTensor])
boxes_maskr/   c                 C  s   t || j| j| jS )a  
        Args:
            boxes_mask: int16 array, sized (num_box, H, W). Each channel represents a box.
                The foreground region in channel c has intensity of labels[c].
                The background intensity is bg_label.

        Return:
            - bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``.
            - classification foreground(fg) labels, dtype should be int, sized (N,).
        )r   r   r   r   )r2   r   r3   r3   r4   r9     s    zMaskToBox.__call__N)r;   r<   r=   r>   r   r@   rA   torchfloat32longr5   r9   r3   r3   r3   r4   r)     s   
c                      sP   e Zd ZdZejejgZdddddddd fddZd	d
ddddZ	  Z
S )r*   a  
    General purpose box cropper when the corresponding image is cropped by SpatialCrop(*) with the same ROI.
    The difference is that we do not support negative indexing for roi_slices.

    If a dimension of the expected ROI size is bigger than the input image size, will not crop that dimension.
    So the cropped result may be smaller than the expected ROI, and the cropped results of several images may
    not have exactly the same shape.
    It can support to crop ND spatial boxes.

    The cropped region can be parameterised in various ways:
        - a list of slices for each spatial dimension (do not allow for use of negative indexing)
        - a spatial center and size
        - the start and end coordinates of the ROI

    Args:
        roi_center: voxel coordinates for center of the crop ROI.
        roi_size: size of the crop ROI, if a dimension of ROI size is bigger than image size,
            will not crop that dimension of the image.
        roi_start: voxel coordinates for start of the crop ROI.
        roi_end: voxel coordinates for end of the crop ROI, if a coordinate is out of image,
            use the end coordinate of image.
        roi_slices: list of slices for each of the spatial dimensions.
    Nz&Sequence[int] | NdarrayOrTensor | NonezSequence[slice] | Noner-   )
roi_centerroi_size	roi_startroi_end
roi_slicesr/   c                   sT   t  ||||| | jD ]4}|jdk sF|jdk sF|jd k	r|jdk rtdqd S )Nr   z@Currently negative indexing is not supported for SpatialCropBox.)superr5   slicesstartstopstepr]   )r2   r   r   r   r   r   rp   	__class__r3   r4   r5     s    
(zSpatialCropBox.__init__r   r{   z-tuple[NdarrayTensor, tuple | NdarrayOrTensor])r7   r}   r/   c                   sX   t t jt|d}t| fddt|D  fddt|D \}}|t||fS )aF  
        Args:
            boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``
            labels: Sequence of array. Each element represents classification labels or scores

        Returns:
            - cropped boxes, does not share memory with original boxes
            - cropped labels, does not share memory with original labels

        Example:
            .. code-block:: python

                box_cropper = SpatialCropPadBox(roi_start=[0, 1, 4], roi_end=[21, 15, 8])
                boxes = torch.ones(2, 6)
                class_labels = torch.Tensor([0, 1])
                pred_scores = torch.Tensor([[0.4,0.3,0.3], [0.5,0.1,0.4]])
                labels = (class_labels, pred_scores)
                boxes_crop, labels_crop_tuple = box_cropper(boxes, labels)
        rQ   c                   s   g | ]} j | jqS r3   )r   r   rT   re   r2   r3   r4   rW     s     z+SpatialCropBox.__call__.<locals>.<listcomp>c                   s   g | ]} j | jqS r3   )r   r   r   r   r3   r4   rW     s     )minrs   r   r   r   ranger   )r2   r7   r}   r.   Z
boxes_cropr~   r3   r   r4   r9     s    zSpatialCropBox.__call__)NNNNN)r;   r<   r=   r>   r   r?   r@   rA   r5   r9   __classcell__r3   r3   r   r4   r*     s        c                   @  s.   e Zd ZdZejejgZddddddZdS )r+   a  
    Rotate a boxes by 90 degrees in the plane specified by `axes`.
    See box_ops.rot90_boxes for additional details

    Args:
        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.
            If axis is negative it counts from the last to the first axis.
    r   rj   )r7   rl   r/   c                 C  s   t ||| j| jS )zm
        Args:
            img: channel first array, must have shape: (num_channels, H[, W, ..., ]),
        )r   kspatial_axesry   r3   r3   r4   r9   /  s    zRotateBox90.__call__NrI   r3   r3   r3   r4   r+   !  s   )7r>   
__future__r   typingr   r   numpyr`   r   monai.config.type_definitionsr   r   r   Zmonai.data.box_utilsr   r	   r
   r   r   r   r   monai.transformsr   r   monai.transforms.transformr   monai.utilsr   r   r   r   monai.utils.enumsr   box_opsr   r   r   r   r   r   r   r   __all__r    r"   r!   r#   r$   r%   r&   r'   r(   r)   r*   r+   r3   r3   r3   r4   <module>   sH   $	(E'671%&G