U Ph @sdZddlmZddlZddlZddlmZmZddlm Z m Z ddl m Z ddl ZddlZddlmZmZddlmZdd lmZdd lmZmZd d gZd ZejZGdddeZGdddeZGdddeZ GdddeZ!GdddeZ"GdddeZ#ee e!e"e#gZ$eZ%d`dddddddd Z&dad!dd"d#d$Z'd%dd%d&d'd(Z(dbd%d!d!d%d)d*d+Z)dcd%d!d%d,d-d.Z*d%d%d/d0d1Z+ddd%d%d3d%d4d5d6Z,ded%d%d8d9d:d;d<Z-d%d8d/d=d>Z.d%d%d/d?d@Z/ejfdAdAdBdCdDdEdFZ0d%d%d%dGdHdIZ1d%d%d%dGdJdKZ2d%d%d%dGdLdMZ3dfdNdOdOd8dPdQdRdSZ4dgd%dOd8dTdUdVdWZ5dXe1fd%d%d3ddYd%dZd[d\Z6dXe1fd%d%d%d3ddYd%d]d^d_Z7dS)ha This utility module mainly supports rectangular bounding boxes with a few different parameterizations and methods for converting between them. It provides reliable access to the spatial coordinates of the box vertices in the "canonical ordering": [xmin, ymin, xmax, ymax] for 2D and [xmin, ymin, zmin, xmax, ymax, zmax] for 3D. We currently define this ordering as `monai.data.box_utils.StandardMode` and the rest of the detection pipelines mainly assumes boxes in `StandardMode`. ) annotationsN)ABCabstractmethod)CallableSequence)deepcopy)NdarrayOrTensor NdarrayTensor)look_up_option) BoxModeName)convert_data_typeconvert_to_dst_typegc@sZeZdZUdZiZded<edddddZed d d d d Z edd dddZ dS)BoxModea+ An abstract class of a ``BoxMode``. A ``BoxMode`` is callable that converts box mode of ``boxes``, which are Nx4 (2D) or Nx6 (3D) torch tensor or ndarray. ``BoxMode`` has several subclasses that represents different box modes, including - :class:`~monai.data.box_utils.CornerCornerModeTypeA`: represents [xmin, ymin, xmax, ymax] for 2D and [xmin, ymin, zmin, xmax, ymax, zmax] for 3D - :class:`~monai.data.box_utils.CornerCornerModeTypeB`: represents [xmin, xmax, ymin, ymax] for 2D and [xmin, xmax, ymin, ymax, zmin, zmax] for 3D - :class:`~monai.data.box_utils.CornerCornerModeTypeC`: represents [xmin, ymin, xmax, ymax] for 2D and [xmin, ymin, xmax, ymax, zmin, zmax] for 3D - :class:`~monai.data.box_utils.CornerSizeMode`: represents [xmin, ymin, xsize, ysize] for 2D and [xmin, ymin, zmin, xsize, ysize, zsize] for 3D - :class:`~monai.data.box_utils.CenterSizeMode`: represents [xcenter, ycenter, xsize, ysize] for 2D and [xcenter, ycenter, zcenter, xsize, ysize, zsize] for 3D We currently define ``StandardMode`` = :class:`~monai.data.box_utils.CornerCornerModeTypeA`, and monai detection pipelines mainly assume ``boxes`` are in ``StandardMode``. The implementation should be aware of: - remember to define class variable ``name``, a dictionary that maps ``spatial_dims`` to :class:`~monai.utils.enums.BoxModeName`. - :func:`~monai.data.box_utils.BoxMode.boxes_to_corners` and :func:`~monai.data.box_utils.BoxMode.corners_to_boxes` should not modify inputs in place. zdict[int, BoxModeName]nameintstr) spatial_dimsreturncCs |j|jS)z Get the mode name for the given spatial dimension using class variable ``name``. Args: spatial_dims: number of spatial dimensions of the bounding boxes. Returns: ``str``: mode string name )rvalue)clsrrI/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/data/box_utils.pyget_nameTs zBoxMode.get_name torch.TensortupleboxesrcCstd|jjddS)a` Convert the bounding boxes of the current mode to corners. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor Returns: ``tuple``: corners of boxes, 4-element or 6-element tuple, each element is a Nx1 torch tensor. It represents (xmin, ymin, xmax, ymax) or (xmin, ymin, zmin, xmax, ymax, zmax) Example: .. code-block:: python boxes = torch.ones(10,6) boxmode = BoxMode() boxmode.boxes_to_corners(boxes) # will return a 6-element tuple, each element is a 10x1 tensor Subclass  must implement this method.NNotImplementedError __class____name__)selfrrrrboxes_to_cornersaszBoxMode.boxes_to_cornersrcornersrcCstd|jjddS)a Convert the given box corners to the bounding boxes of the current mode. Args: corners: corners of boxes, 4-element or 6-element tuple, each element is a Nx1 torch tensor. It represents (xmin, ymin, xmax, ymax) or (xmin, ymin, zmin, xmax, ymax, zmax) Returns: ``Tensor``: bounding boxes, Nx4 or Nx6 torch tensor Example: .. code-block:: python corners = (torch.ones(10,1), torch.ones(10,1), torch.ones(10,1), torch.ones(10,1)) boxmode = BoxMode() boxmode.corners_to_boxes(corners) # will return a 10x4 tensor rr Nr!)r%r(rrrcorners_to_boxesvszBoxMode.corners_to_boxesN) r$ __module__ __qualname____doc__r__annotations__ classmethodrrr&r)rrrrr4s   rc@s>eZdZdZejejdZdddddZddd d d Z d S) CornerCornerModeTypeAav A subclass of ``BoxMode``. Also represented as "xyxy" or "xyzxyz", with format of [xmin, ymin, xmax, ymax] or [xmin, ymin, zmin, xmax, ymax, zmax]. Example: .. code-block:: python CornerCornerModeTypeA.get_name(spatial_dims=2) # will return "xyxy" CornerCornerModeTypeA.get_name(spatial_dims=3) # will return "xyzxyz" rrrrrcCs|jddd}|S)Ndim)split)r%rr(rrrr&sz&CornerCornerModeTypeA.boxes_to_cornersrr'cCstjt|dd}|S)Nr2r3)torchcatr)r%r(rrrrr)sz&CornerCornerModeTypeA.corners_to_boxesN) r$r*r+r,r XYXYXYZXYZrr&r)rrrrr/s r/c@s>eZdZdZejejdZdddddZddd d d Z d S) CornerCornerModeTypeBav A subclass of ``BoxMode``. Also represented as "xxyy" or "xxyyzz", with format of [xmin, xmax, ymin, ymax] or [xmin, xmax, ymin, ymax, zmin, zmax]. Example: .. code-block:: python CornerCornerModeTypeB.get_name(spatial_dims=2) # will return "xxyy" CornerCornerModeTypeB.get_name(spatial_dims=3) # will return "xxyyzz" r0rrrc Cslt|d}|dkr>|jddd\}}}}}}||||||f} n*|dkrh|jddd\}}}}||||f} | SNrrr1r2r3rget_spatial_dimsr5) r%rrxminxmaxyminymaxzminzmaxr(rrrr&s  z&CornerCornerModeTypeB.boxes_to_cornersrr'cCsxt|d}|dkrFtj|d|d|d|d|d|dfdd }n.|dkrttj|d|d|d|dfdd }|S Nr(rrr1rr2r3)r>r6r7r%r(rrrrrr)s  4&z&CornerCornerModeTypeB.corners_to_boxesN) r$r*r+r,r XXYYXXYYZZrr&r)rrrrr:s  r:c@s>eZdZdZejejdZdddddZddd d d Z d S) CornerCornerModeTypeCav A subclass of ``BoxMode``. Also represented as "xyxy" or "xyxyzz", with format of [xmin, ymin, xmax, ymax] or [xmin, ymin, xmax, ymax, zmin, zmax]. Example: .. code-block:: python CornerCornerModeTypeC.get_name(spatial_dims=2) # will return "xyxy" CornerCornerModeTypeC.get_name(spatial_dims=3) # will return "xyxyzz" r0rrrc CsXt|d}|dkr>|jddd\}}}}}}||||||f} n|dkrT|jddd} | Sr;r=) r%rrr?rAr@rBrCrDr(rrrr&s z&CornerCornerModeTypeC.boxes_to_cornersrr'cCsdt|d}|dkrFtj|d|d|d|d|d|dfdd }n|dkr`tjt|dd }|SrE)r>r6r7rrIrrrr)s  4z&CornerCornerModeTypeC.corners_to_boxesN) r$r*r+r,r r8XYXYZZrr&r)rrrrrLs  rLc@s>eZdZdZejejdZdddddZddd d d Z d S) CornerSizeModeam A subclass of ``BoxMode``. Also represented as "xywh" or "xyzwhd", with format of [xmin, ymin, xsize, ysize] or [xmin, ymin, zmin, xsize, ysize, zsize]. Example: .. code-block:: python CornerSizeMode.get_name(spatial_dims=2) # will return "xywh" CornerSizeMode.get_name(spatial_dims=3) # will return "xyzwhd" r0rrrcCs(|j}t|d}|dkr|jddd\}}}}}} ||tjtdjddj|d} ||tjtdjddj|d} || tjtdjddj|d} |||| | | f} nt|d kr$|jddd\}}}}||tjtdjddj|d} ||tjtdjddj|d} ||| | f} | S) Nr<rr1r2r3dtyperminrrPr>r5 TO_REMOVEto COMPUTE_DTYPEclamp)r%r box_dtyperr?rArCwhdr@rBrDr(rrrr&s $$$ $$ zCornerSizeMode.boxes_to_cornersrr'c Cst|d}|dkrz|d|d|d|d|d|df\}}}}}}tj|||||t||t||tfdd } nR|dkr|d|d|d|df\}}}}tj||||t||tfdd } | S) NrFrrr1rrGrHr2r3r>r6r7rT r%r(rr?rArCr@rBrDrrrrr)s 4&$&zCornerSizeMode.corners_to_boxesN) r$r*r+r,r XYWHXYZWHDrr&r)rrrrrNs rNc@s>eZdZdZejejdZdddddZddd d d Z d S) CenterSizeModeam A subclass of ``BoxMode``. Also represented as "ccwh" or "cccwhd", with format of [xmin, ymin, xsize, ysize] or [xmin, ymin, zmin, xsize, ysize, zsize]. Example: .. code-block:: python CenterSizeMode.get_name(spatial_dims=2) # will return "ccwh" CenterSizeMode.get_name(spatial_dims=3) # will return "cccwhd" r0rrrcCs|j}t|d}|dkr6|jddd\}}}}}} ||tdjtdjdd j|d} ||tdjtdjdd j|d} ||tdjtdjdd j|d} ||tdjtdjdd j|d} || tdjtdjdd j|d}|| tdjtdjdd j|d}| | || | |f}n|d kr|jddd\}}}}||tdjtdjdd j|d} ||tdjtdjdd j|d} ||tdjtdjdd j|d} ||tdjtdjdd j|d} | | | | f}|S) Nr<rr1r2r3@rOrrQrrS)r%rrXrxcyczcrYrZr[r?r@rArBrCrDr(rrrr&1s&  (((((( (((( zCenterSizeMode.boxes_to_cornersrr'c Cst|d}|dkr|d|d|d|d|d|df\}}}}}}tj||td||td||td||t||t||tfd d } nl|dkr |d|d|d|df\}}}}tj||td||td||t||tfd d } | S) NrFrrr1rrGrHrar2r3r\r]rrrr)Is0 4    $   zCenterSizeMode.corners_to_boxesN) r$r*r+r,r CCWHCCCWHDrr&r)rrrrr`!s r`z torch.Tensor | np.ndarray | NonezSequence | Nonez0Sequence[int] | torch.Tensor | np.ndarray | Noner)rpointsr( spatial_sizercCst}|dk rt|jdkrP|jddkr>td|jdntd|jdt|jddtkrxtd|jd|t|jdd|dk rt|jdkr|jddkrtd|jd ntd|jdt|jdtkrtd|jd|t|jd|dk rXt|dtkrFtd t|d|t|d|dk rt|tkrtd |d|t|t|}t|dkrtd t|dkrt|d}t|dd gd}t|StddS)a1 Get spatial dimension for the giving setting and check the validity of them. Missing input is allowed. But at least one of the input value should be given. It raises ValueError if the dimensions of multiple inputs do not match with each other. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray points: point coordinates, [x, y] or [x, y, z], Nx2 or Nx3 torch tensor or ndarray corners: corners of boxes, 4-element or 6-element tuple, each element is a Nx1 torch tensor or ndarray spatial_size: The spatial size of the image where the boxes are attached. len(spatial_size) should be in [2, 3]. Returns: ``int``: spatial_dims, number of spatial dimensions of the bounding boxes. Example: .. code-block:: python boxes = torch.ones(10,6) get_spatial_dims(boxes, spatial_size=[100,200,200]) # will return 3 get_spatial_dims(boxes, spatial_size=[100,200]) # will raise ValueError get_spatial_dims(boxes) # will return 3 NrrzPCurrently we support only boxes with shape [N,4] or [N,6], got boxes with shape z^. Please reshape it with boxes = torch.reshape(boxes, [0, 4]) or torch.reshape(boxes, [0, 6])..r1zRCurrently we support only points with shape [N,2] or [N,3], got points with shape za. Please reshape it with points = torch.reshape(points, [0, 2]) or torch.reshape(points, [0, 3]).z\Currently we support only boxes with shape [N,4] or [N,6], got box corner tuple with length zNCurrently we support only boxes on 2-D and 3-D images, got image spatial_size z1At least one of the inputs needs to be non-empty.r) supportedz?The dimensions of multiple inputs should match with each other.) setlenshape ValueErrorrSUPPORTED_SPATIAL_DIMSaddlistr )rrgr(rhZspatial_dims_setZspatial_dims_listrrrrr>msb           r>z$str | BoxMode | type[BoxMode] | None)modercOst|tr|St|r,t|tr,|||St|tr~tD]B}tD]8}t|rBt|trB|||krB|||SqBq:|dk rt d|dt ||S)a` This function that return a :class:`~monai.data.box_utils.BoxMode` object giving a representation of box mode Args: mode: a representation of 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. 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()`` Returns: BoxMode object Example: .. code-block:: python mode = "xyzxyz" get_boxmode(mode) # will return CornerCornerModeTypeA() NzUnsupported box mode: ri) isinstancerinspectisclass issubclassrSUPPORTED_MODESrorrn StandardMode)rrargskwargsmnrrr get_boxmodes-   "r}r)rrrcCsFt|tj^}}|jddkr2t|d|dg}t||d^}}|S)a When boxes are empty, this function standardize it to shape of (0,4) or (0,6). Args: boxes: bounding boxes, Nx4 or Nx6 or empty torch tensor or ndarray spatial_dims: number of spatial dimensions of the bounding boxes. Returns: bounding boxes with shape (N,4) or (N,6), N can be 0. Example: .. code-block:: python boxes = torch.ones(0,) standardize_empty_box(boxes, 3) rrsrcdst)r r6Tensorrmreshaper )rrboxes_t_ boxes_dstrrrstandardize_empty_boxs r)rsrc_modedst_moderc Cs|jddkr|St|}t|}t|t|r8t|St|tj^}}||}t |d}t d|D]*} ||| || k dkrft dqf||} t| |d^} }| S)a This function converts the boxes in src_mode to the dst_mode. Args: boxes: source bounding boxes, Nx4 or Nx6 torch tensor or ndarray. src_mode: source box mode. If it is not given, this func will assume it is ``StandardMode()``. It follows the same format with ``mode`` in :func:`~monai.data.box_utils.get_boxmode`. dst_mode: target box mode. If it is not given, this func will assume it is ``StandardMode()``. It follows the same format with ``mode`` in :func:`~monai.data.box_utils.get_boxmode`. Returns: bounding boxes with target mode, with same data type as ``boxes``, does not share memory with ``boxes`` Example: .. code-block:: python boxes = torch.ones(10,4) # The following three lines are equivalent # They convert boxes with format [xmin, ymin, xmax, ymax] to [xcenter, ycenter, xsize, ysize]. convert_box_mode(boxes=boxes, src_mode="xyxy", dst_mode="ccwh") convert_box_mode(boxes=boxes, src_mode="xyxy", dst_mode=monai.data.box_utils.CenterSizeMode) convert_box_mode(boxes=boxes, src_mode="xyxy", dst_mode=monai.data.box_utils.CenterSizeMode()) rr<BGiven boxes has invalid values. The box size must be non-negative.r~)rmr}rstyperr r6rr&r>rangesumwarningswarnr)r ) rrrZ src_boxmodeZ dst_boxmoderrr(raxisZ boxes_t_dstrrrrconvert_box_mode"s    r)rrrrcCst||tdS)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. mode: source box mode. If it is not given, this func will assume it is ``StandardMode()``. It follows the same format with ``mode`` in :func:`~monai.data.box_utils.get_boxmode`. Returns: bounding boxes with standard mode, with same data type as ``boxes``, does not share memory with ``boxes`` Example: .. code-block:: python boxes = torch.ones(10,6) # The following two lines are equivalent # They convert boxes with format [xmin, xmax, ymin, ymax, zmin, zmax] to [xmin, ymin, zmin, xmax, ymax, zmax] convert_box_to_standard_mode(boxes=boxes, mode="xxyyzz") convert_box_mode(boxes=boxes, src_mode="xxyyzz", dst_mode="xyzxyz") rrr)rrx)rrrrrrconvert_box_to_standard_mode^srrcCs(t|d}t|ttdddd|fS)z Compute center points of boxes Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` Returns: center points with size of (N, spatial_dims) r<rN)r>rrxr`)rrrrr box_centerszs r{Gz?float)centersrepsrcstdfddtDfddtD}ttjrftj|ddjdd}||kStj|ddt jddd|kS) a Checks which center points are within boxes Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode``. centers: center points, Nx2 or Nx3 torch tensor or ndarray. eps: minimum distance to border of boxes. Returns: boolean array indicating which center points are within the boxes, sized (N,). Reference: https://github.com/MIC-DKFZ/nnDetection/blob/main/nndet/core/boxes/ops.py r<cs,g|]$}dd|fdd|fqSNr.0r)rrrr sz$centers_in_boxes..cs0g|](}dd|fdd|fqSrrrrrrrrrsr1)rr3r) r>rrsnpndarraystackrRr6rUrV)rrrZcenter_to_borderZmin_center_to_borderrrrcenters_in_boxess $ rTboolz8tuple[NdarrayOrTensor, NdarrayOrTensor, NdarrayOrTensor])boxes1boxes2 euclideanrc Cst|t|s8tdt|dt|dt|dt|tj^}}t|tj^}}t|t }t|t }|r|dddf|d d d }n|dddf|d d}t |||f|d^\}}}}|||fS) aB Distance of center points between two sets of boxes Args: boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` boxes2: bounding boxes, Mx4 or Mx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` euclidean: computed the euclidean distance otherwise it uses the l1 distance Returns: - The pairwise distances for every element in boxes1 and boxes2, with size of (N,M) and same data type as ``boxes1``. - Center points of boxes1, with size of (N,spatial_dims) and same data type as ``boxes1``. - Center points of boxes2, with size of (M,spatial_dims) and same data type as ``boxes1``. Reference: https://github.com/MIC-DKFZ/nnDetection/blob/main/nndet/core/boxes/ops.py boxes1 is , while boxes2 is . The result will be riNrr2r~)rsrrrr r6rrrUrVpowrsqrtr ) rrrboxes1_trboxes2_tZcenter1Zcenter2distsrrrboxes_center_distances**rcCsPt|d}td|D]6}|dd||f|dd|fkdkrdSqdS)z This function checks whether the box size is non-negative. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` Returns: whether ``boxes`` is valid r<rNFT)r>rr)rrrrrris_valid_box_valuess ,rcCst|stdt|d}|dd|f|dddft}td|D]0}||dd||f|dd|ft}qHt|tj^}}| s| r|j tj krtdntd|S)a This function computes the area (2D) or volume (3D) of each box. Half precision is not recommended for this function as it may cause overflow, especially for 3D images. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` Returns: area (2D) or volume (3D) of boxes, with size of (N,). Example: .. code-block:: python boxes = torch.ones(10,6) # we do computation with torch.float32 to avoid overflow compute_dtype = torch.float32 area = box_area(boxes=boxes.to(dtype=compute_dtype)) # torch.float32, size of (10,) rr<Nrr1zUBox area is NaN or Inf. boxes is float16. Please change to float32 and test it again.zBox area is NaN or Inf.) rrnr>rTrr r6risnananyisinfrPfloat16)rrarearZarea_trrrrbox_areas $.  rrz torch.dtypez!tuple[torch.Tensor, torch.Tensor])rr compute_dtyperc Cst|d}t|j|dd}t|j|dd}t|dddd|f|ddd|fj|d}t|ddd|df|dd|dfj|d}||tjdd}tj|ddd} |dddf|| } | | fS) a( This internal function computes the intersection and union area of two set of boxes. Args: boxes1: bounding boxes, Nx4 or Nx6 torch tensor. The box mode is assumed to be ``StandardMode`` boxes2: bounding boxes, Mx4 or Mx6 torch tensor. The box mode is assumed to be ``StandardMode`` compute_dtype: default torch.float32, dtype with which the results will be computed Returns: inter, with size of (N,M) and dtype of ``compute_dtype``. union, with size of (N,M) and dtype of ``compute_dtype``. r<rONrrQr2Fr4keepdim) r>rrUr6maxrRrTrWprod) rrrrarea1area2ltrbwhinterunionrrr_box_inter_unions ..r)rrrc Cst|t|s8tdt|dt|dt|dt|tj^}}t|tj^}}|j}t||t d\}}||t t j }|j |d}t |st|rtdt||d^} }| S) a Compute the intersection over union (IoU) of two set of boxes. Args: boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` boxes2: bounding boxes, Mx4 or Mx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` Returns: IoU, with size of (N,M) and same data type as ``boxes1`` rrrrirrOzBox IoU is NaN or Inf.r~)rsrrrr r6rrPrrVfinforrUrrrrnr ) rrrrrrXrrZiou_tiourrrbox_iou4s * rc Cst|t|s8tdt|dt|dt|dt|tj^}}t|tj^}}t|d}|j}t ||t d\}}||t t j } t |dddd|f|ddd|fjt d} t|ddd|df|dd|dfjt d} | | tjd d } tj| d d d } | | || t t j }|j|d}t|sft|rntdt||d^}}|S)a Compute the generalized intersection over union (GIoU) of two sets of boxes. The two inputs can have different shapes and the func return an NxM matrix, (in contrary to :func:`~monai.data.box_utils.box_pair_giou` , which requires the inputs to have the same shape and returns ``N`` values). Args: boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` boxes2: bounding boxes, Mx4 or Mx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` Returns: GIoU, with size of (N,M) and same data type as ``boxes1`` Reference: https://giou.stanford.edu/GIoU.pdf rrrrir<rNrOrrQr2FrBox GIoU is NaN or Inf.r~)rsrrrr r6rr>rPrrVrrrRrUrrTrWrrrrrnr )rrrrrrrXrrrrrr enclosuregiou_tgiourrrbox_giouZs,* ..  rc Cs<t|t|s8tdt|dt|dt|dt|tj^}}t|tj^}}|j|jkrltdt |d}|j }t |j t dd}t |j t dd}t|ddd|f|ddd|fj t d} t|dd|df|dd|dfj t d} | | tjd d } tj| d d d } ||| } | | tt j}t|ddd|f|ddd|fj t d} t|dd|df|dd|dfj t d} | | tjd d } tj| d d d }||| |tt j}|j |d}t|s t|r(tdt||d^}}|S)a Compute the generalized intersection over union (GIoU) of a pair of boxes. The two inputs should have the same shape and the func return an (N,) array, (in contrary to :func:`~monai.data.box_utils.box_giou` , which does not require the inputs to have the same shape and returns ``NxM`` matrix). Args: boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` boxes2: bounding boxes, same shape with boxes1. The box mode is assumed to be ``StandardMode`` Returns: paired GIoU, with size of (N,) and same data type as ``boxes1`` Reference: https://giou.stanford.edu/GIoU.pdf rrrriz7boxes1 and boxes2 should be paired and have same shape.r<rONrrQr2Frrr~)rsrrrr r6rrmrnr>rPrrUrVrrRrTrWrrrrrrr )rrrrrrrXrrrrrrrrrrrrrr box_pair_giousD*  ,, ,,  rr zSequence[int] | NdarrayOrTensorz%tuple[NdarrayTensor, NdarrayOrTensor])r roi_startroi_end remove_emptyrc Cst|tjd}|jtd}t||dddtj}t||dddtj}t||}t ||d}t d|D]}|dd|fj ||||t d|dd|f<|dd||fj ||||t d|dd||f<|dd|f||8<|dd||f||8<qv|r|dd|f|dddfdt k} t d|D]6}| |dd||f|dd|fdt k@} q\|| }ntj |dddfdtjd } t||d ^} } t| || jd ^} } | | fS) a This function generate the new boxes when the corresponding image is cropped to the given ROI. When ``remove_empty=True``, it makes sure the bounding boxes are within the new cropped image. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` roi_start: voxel coordinates for start of the crop ROI, negative values allowed. roi_end: voxel coordinates for end of the crop ROI, negative values allowed. remove_empty: whether to remove the boxes that are actually empty Returns: - cropped boxes, boxes[keep], does not share memory with original boxes - ``keep``, it indicates whether each box in ``boxes`` are kept when ``remove_empty=True``. rrOT)rr wrap_sequencerrhN)rRrr1) fill_valuerPr~rrrP)r r6rclonerUrVr int16maximumr>rrWrT full_likerrP) rrrrrZ roi_start_tZ roi_end_trrZkeep_tZ boxes_keeprkeeprrrspatial_crop_boxess.   2 "(4 rz'tuple[NdarrayOrTensor, NdarrayOrTensor])rrhrrcCs"t||d}t|dg|||dS)ad This function clips the ``boxes`` to makes sure the bounding boxes are within the image. Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` spatial_size: The spatial size of the image where the boxes are attached. len(spatial_size) should be in [2, 3]. remove_empty: whether to remove the boxes that are actually empty Returns: - clipped boxes, boxes[keep], does not share memory with original boxes - ``keep``, it indicates whether each box in ``boxes`` are kept when ``remove_empty=True``. rr)rrr)r>r)rrhrrrrrclip_boxes_to_images rr2r)rscores nms_thresh max_proposalsbox_overlap_metricrcCsr|jddkr(ttg|tjddS|jd|jdkrTtd|jd|jt|tj^}}t||^}}tj |ddd}t ||ddf} g} tt t d| jdj |jtjd} t| dkrVt| d} | | t| |krd krnnqV|| | ddf| | | d ddf} | |k}d |d<| |} q|| }t|||jddS) a Non-maximum suppression (NMS). Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` scores: prediction scores of the boxes, sized (N,). This function keeps boxes with higher scores. nms_thresh: threshold of NMS. Discards all overlapping boxes with box_overlap > nms_thresh. max_proposals: maximum number of boxes it keeps. If ``max_proposals`` = -1, there is no limit on the number of boxes that are kept. box_overlap_metric: the metric to compute overlap between boxes. Returns: Indexes of ``boxes`` that are kept after NMS. Example: .. code-block:: python boxes = torch.ones(10,6) scores = torch.ones(10) keep = non_max_suppression(boxes, scores, num_thresh=0.1) boxes_after_nms = boxes[keep] rrz:boxes and scores should have same length, got boxes shape z, scores shape T)r4 descendingN)devicerPr1F)rmr rarrayr6longrnr rargsortrrqrrUrrlritemappendflattenrP)rrrrrrrscores_tZ sort_idxsZ boxes_sortpickidxsiZ box_overlapZ to_keep_idxZpick_idxrrrnon_max_suppression.s.(  *  r)rrlabelsrrrrcCs|jddkr(ttg|tjddSt|tjtjd^}}t||^}}t||tjd^} }| } | || d} || dddf} t | ||||} t| || j ddS)a Performs non-maximum suppression in a batched fashion. Each labels value correspond to a category, and NMS will not be applied between elements of different categories. Adapted from https://github.com/MIC-DKFZ/nnDetection/blob/main/nndet/core/boxes/nms.py Args: boxes: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` scores: prediction scores of the boxes, sized (N,). This function keeps boxes with higher scores. labels: indices of the categories for each one of the boxes. sized(N,), value range is (0, num_classes) nms_thresh: threshold of NMS. Discards all overlapping boxes with box_overlap > nms_thresh. max_proposals: maximum number of boxes it keeps. If ``max_proposals`` = -1, there is no limit on the number of boxes that are kept. box_overlap_metric: the metric to compute overlap between boxes. Returns: Indexes of ``boxes`` that are kept after NMS. rrrOr1N) rmr rrr6rr rfloat32rrUrrP)rrrrrrrrrZlabels_tZmax_coordinateoffsetsZ boxes_for_nmsrrrr batched_nmsxsr)NNNN)N)NN)N)r)T)T)T)8r, __future__rrtrabcrrcollections.abcrrcopyrnumpyrr6monai.config.type_definitionsrr monai.utilsr monai.utils.enumsr Zmonai.utils.type_conversionr r rorTrrVrr/r:rLrNr`rwrxr>r}rrrrrrrrrrrrrrrrrrrr sp    X%$1G\>= ++&&:R:O