U Ph_ @sdZddlmZddlmZmZddlZddlZddl m Z m Z m Z ddl mZmZmZmZmZmZmZddlmZmZddlmZdd lmZmZmZmZdd lm Z d d l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)d dddddddddddg Z*Gdd d eZ+GdddeZ,GdddeZ-GdddeZ.GdddeZ/GdddeZ0GdddeZ1Gd ddeZ2Gd!ddeZ3Gd"ddeZ4Gd#ddeZ5Gd$ddeZ6dS)%zr A collection of "vanilla" transforms for box operations https://github.com/Project-MONAI/MONAI/wiki/MONAI_Design ) annotations)AnySequenceN) DtypeLikeNdarrayOrTensor NdarrayTensor)BoxModeclip_boxes_to_imageconvert_box_modeconvert_box_to_standard_modeget_spatial_dimsspatial_crop_boxesstandardize_empty_box)Rotate90 SpatialCrop) Transform) ensure_tupleensure_tuple_repfall_back_tuplelook_up_option)TransformBackends)apply_affine_to_boxesconvert_box_to_maskconvert_mask_to_box flip_boxes resize_boxes rot90_boxes select_labels zoom_boxesStandardizeEmptyBoxConvertBoxToStandardModeConvertBoxMode AffineBoxZoomBox ResizeBoxFlipBoxClipBoxToImage BoxToMask MaskToBoxSpatialCropBox RotateBox90c@s<eZdZdZejejgZdddddZdddd 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. intNone) spatial_dimsreturncCs ||_dSNr.)selfr.r3Z/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/apps/detection/transforms/array.py__init__KszStandardizeEmptyBox.__init__rboxesr/cCst||jdS)zl Args: boxes: source bounding boxes, Nx4 or Nx6 or 0xM torch tensor or ndarray. r1)rr.r2r7r3r3r4__call__NszStandardizeEmptyBox.__call__N __name__ __module__ __qualname____doc__rTORCHNUMPYbackendr5r9r3r3r3r4r As c@s@eZdZdZejejgZd ddddddZddd d d Z dS) 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_modedst_moder/cCs||_||_dSr0rCrD)r2rCrDr3r3r4r5szConvertBoxMode.__init__rr6cCst||j|jdS)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 rCrDr8r3r3r4r9s zConvertBoxMode.__call__)NNr:r3r3r3r4r"Vs - c@s>eZdZdZejejgZd dddddZddd d d Z dS) 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) NrBr-)moder/cCs ||_dSr0rF)r2rFr3r3r4r5sz!ConvertBoxToStandardMode.__init__rr6cCst||jdS)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 rFr8r3r3r4r9s z!ConvertBoxToStandardMode.__call__)Nr:r3r3r3r4r!s c@s.eZdZdZejejgZddddddZdS)r#z, Applies affine matrix to the boxes rzNdarrayOrTensor | None)r7affiner/cCs|dkr |St||dS)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)r2r7rHr3r3r4r9szAffineBox.__call__N r;r<r=r>rr?r@rAr9r3r3r3r4r#s c@sFeZdZdZejejgZdddddddd Zdd d d d ddZ 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. FzSequence[float] | floatboolrr-)zoom keep_sizekwargsr/cKs||_||_||_dSr0)rKrLrM)r2rKrLrMr3r3r4r5szZoomBox.__init__NrSequence[int] | int | Noner7src_spatial_sizer/c Csrt|d}t|j||_|js*t||jS|dkr:tdt||}ddt|j|D}tddt||D|_t||j}t t |t |snt t||D]\}\}}||} t | d} | d kr|dd|f| |dd|f<|dd||f| |dd||f<q| d kr|dd|f| |dd|f<|dd||f| |dd||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. r7Nz2keep_size=True, src_spatial_size must be provided.cSs g|]\}}tt||qSr3r,round).0zssr3r3r4 sz$ZoomBox.__call__..css|]\}}|t|VqdSr0)float)rTrVdsr3r3r4 sz#ZoomBox.__call__..r)r rrK_zoomrLr ValueErrorziptuplenpallclosearray enumerateabs) r2r7rPr.Zdst_spatial_sizeZ zoomed_boxesaxisodZzddiffhalfr3r3r4r9s*       * *zZoomBox.__call__)F)Nr:r3r3r3r4r$s c@sDeZdZdZejejgZdddddddd Zd dd d d d Z dS)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. allSequence[int] | intstrrr-) spatial_size size_moderMr/cKst|ddg|_||_dS)Nrilongest)rrmrl)r2rlrmrMr3r3r4r5 szResizeBox.__init__rrOcst|d}t||}|jdkrXtt|j}||krJtd|d|dt|j|}n8t|jt sltd|jt |t fdd|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. rQrizWlen(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'.c3s|]}tt|VqdSr0rR)rTsscaler3r4rZ=sz%ResizeBox.__call__..) r rrmlenrrlr]r isinstancer,maxr_r)r2r7rP input_ndimZsrc_spatial_size_ output_ndimZ spatial_size_r3rqr4r9$s    zResizeBox.__call__N)rir:r3r3r3r4r% s c@s>eZdZdZejejgZd dddddZdd d d d Z dS)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. NrNr-) spatial_axisr/cCs ||_dSr0)rx)r2rxr3r3r4r5QszFlipBox.__init__rrj)r7rlcCst|||jdS)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. )rlZ flip_axes)rrxr2r7rlr3r3r4r9TszFlipBox.__call__)Nr:r3r3r3r4r&Bs c@sBeZdZdZejejgZddddddZdd d d d d dZ dS)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 FrJr-) remove_emptyr/cCs ||_dSr0)rz)r2rzr3r3r4r5iszClipBoxToImage.__init__r+Sequence[NdarrayOrTensor] | NdarrayOrTensorrjz/tuple[NdarrayOrTensor, tuple | NdarrayOrTensor]r7labelsrlr/cCs4t|d}t||}t|||j\}}|t||fS)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 rr rzr)r2r7r}rlr.Z boxes_clipkeepr3r3r4r9ls  zClipBoxToImage.__call__N)Fr:r3r3r3r4r'^s c@s@eZdZdZejgZddddddd Zd d d d d d dZdS)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,rJr-)bg_label ellipse_maskr/cCs||_||_dSr0)rr)r2rrr3r3r4r5szBoxToMask.__init__rrjr|cCst||||j|jS)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. )rrr)r2r7r}rlr3r3r4r9szBoxToMask.__call__N)rF) r;r<r=r>rr@rAr5r9r3r3r3r4r(s c@sHeZdZdZejgZdejej fdddddddZ d d d d d Z dS)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 rr,zDtypeLike | torch.dtyper-)r box_dtype label_dtyper/cCs||_||_||_dSr0)rrr)r2rrrr3r3r4r5szMaskToBox.__init__rz'tuple[NdarrayOrTensor, NdarrayOrTensor]) boxes_maskr/cCst||j|j|jS)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,). )rrrr)r2rr3r3r4r9s zMaskToBox.__call__N) r;r<r=r>rr@rAtorchfloat32longr5r9r3r3r3r4r)s  csPeZdZdZejejgZddddddddfdd Zd d d d d dZ 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 | NonezSequence[slice] | Noner-) roi_centerroi_size roi_startroi_end roi_slicesr/csTt||||||jD]4}|jdksF|jdksF|jdk r|jdkrtdqdS)Nrz@Currently negative indexing is not supported for SpatialCropBox.)superr5slicesstartstopstepr])r2rrrrrrp __class__r3r4r5s (zSpatialCropBox.__init__rr{z-tuple[NdarrayTensor, tuple | NdarrayOrTensor])r7r}r/csXttjt|d}t|fddt|Dfddt|D\}}|t||fS)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) rQcsg|]}j|jqSr3)rrrTrer2r3r4rWsz+SpatialCropBox.__call__..csg|]}j|jqSr3)rrrrr3r4rWs)minrsrr r ranger)r2r7r}r.Z boxes_cropr~r3rr4r9szSpatialCropBox.__call__)NNNNN) r;r<r=r>rr?r@rAr5r9 __classcell__r3r3rr4r*s  c@s.eZdZdZejejgZddddddZdS)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. rrj)r7rlr/cCst|||j|jS)zm Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]), )rk spatial_axesryr3r3r4r9/szRotateBox90.__call__NrIr3r3r3r4r+!s )7r> __future__rtypingrrnumpyr`rmonai.config.type_definitionsrrrZmonai.data.box_utilsrr r r r r rmonai.transformsrrmonai.transforms.transformr monai.utilsrrrrmonai.utils.enumsrbox_opsrrrrrrrr__all__r r"r!r#r$r%r&r'r(r)r*r+r3r3r3r4 sH $   ( E'671%&G