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`` v
(boxes1: NdarrayOrTensor, boxes2: NdarrayOrTensor)
| 861 | |
| 862 | |
| 863 | def box_giou(boxes1: NdarrayOrTensor, boxes2: NdarrayOrTensor) -> NdarrayOrTensor: |
| 864 | """ |
| 865 | Compute the generalized intersection over union (GIoU) of two sets of boxes. |
| 866 | The two inputs can have different shapes and the func return an NxM matrix, |
| 867 | (in contrary to :func:`~monai.data.box_utils.box_pair_giou` , which requires the inputs to have the same |
| 868 | shape and returns ``N`` values). |
| 869 | |
| 870 | Args: |
| 871 | boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` |
| 872 | boxes2: bounding boxes, Mx4 or Mx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` |
| 873 | |
| 874 | Returns: |
| 875 | An array/tensor matching the container type of ``boxes1`` (NumPy ndarray or Torch tensor), always |
| 876 | floating-point with size ``(N, M)``: |
| 877 | - if ``boxes1`` has a floating-point dtype, the same dtype is used. |
| 878 | - if ``boxes1`` has an integer dtype, the result is returned as ``torch.float32``. |
| 879 | |
| 880 | Reference: |
| 881 | https://giou.stanford.edu/GIoU.pdf |
| 882 | |
| 883 | """ |
| 884 | |
| 885 | if not isinstance(boxes1, type(boxes2)): |
| 886 | warnings.warn(f"boxes1 is {type(boxes1)}, while boxes2 is {type(boxes2)}. The result will be {type(boxes1)}.") |
| 887 | |
| 888 | # convert numpy to tensor if needed |
| 889 | boxes1_t, *_ = convert_data_type(boxes1, torch.Tensor) |
| 890 | boxes2_t, *_ = convert_data_type(boxes2, torch.Tensor) |
| 891 | |
| 892 | spatial_dims = get_spatial_dims(boxes=boxes1_t) |
| 893 | |
| 894 | # we do computation with compute_dtype to avoid overflow |
| 895 | box_dtype = boxes1_t.dtype |
| 896 | |
| 897 | inter, union = _box_inter_union(boxes1_t, boxes2_t, compute_dtype=COMPUTE_DTYPE) |
| 898 | iou = inter / (union + torch.finfo(COMPUTE_DTYPE).eps) # (N,M) |
| 899 | |
| 900 | # Enclosure |
| 901 | # get the left top and right bottom points for the NxM combinations |
| 902 | lt = torch.min(boxes1_t[:, None, :spatial_dims], boxes2_t[:, :spatial_dims]).to( |
| 903 | dtype=COMPUTE_DTYPE |
| 904 | ) # (N,M,spatial_dims) left top |
| 905 | rb = torch.max(boxes1_t[:, None, spatial_dims:], boxes2_t[:, spatial_dims:]).to( |
| 906 | dtype=COMPUTE_DTYPE |
| 907 | ) # (N,M,spatial_dims) right bottom |
| 908 | |
| 909 | # compute size for the enclosure region for the NxM combinations |
| 910 | wh = (rb - lt + TO_REMOVE).clamp(min=0) # (N,M,spatial_dims) |
| 911 | enclosure = torch.prod(wh, dim=-1, keepdim=False) # (N,M) |
| 912 | |
| 913 | # GIoU |
| 914 | giou_t = iou - (enclosure - union) / (enclosure + torch.finfo(COMPUTE_DTYPE).eps) |
| 915 | if not box_dtype.is_floating_point: |
| 916 | box_dtype = COMPUTE_DTYPE |
| 917 | giou_t = giou_t.to(dtype=box_dtype) |
| 918 | |
| 919 | if torch.isnan(giou_t).any() or torch.isinf(giou_t).any(): |
| 920 | raise ValueError("Box GIoU is NaN or Inf.") |
nothing calls this directly
no test coverage detected
searching dependent graphs…