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
(boxes1: NdarrayOrTensor, boxes2: NdarrayOrTensor)
| 925 | |
| 926 | |
| 927 | def box_pair_giou(boxes1: NdarrayOrTensor, boxes2: NdarrayOrTensor) -> NdarrayOrTensor: |
| 928 | """ |
| 929 | Compute the generalized intersection over union (GIoU) of a pair of boxes. |
| 930 | The two inputs should have the same shape and the func return an (N,) array, |
| 931 | (in contrary to :func:`~monai.data.box_utils.box_giou` , which does not require the inputs to have the same |
| 932 | shape and returns ``NxM`` matrix). |
| 933 | |
| 934 | Args: |
| 935 | boxes1: bounding boxes, Nx4 or Nx6 torch tensor or ndarray. The box mode is assumed to be ``StandardMode`` |
| 936 | boxes2: bounding boxes, same shape with boxes1. The box mode is assumed to be ``StandardMode`` |
| 937 | |
| 938 | Returns: |
| 939 | An array/tensor matching the container type of ``boxes1`` (NumPy ndarray or Torch tensor), always |
| 940 | floating-point with size ``(N, )``: |
| 941 | - if ``boxes1`` has a floating-point dtype, the same dtype is used. |
| 942 | - if ``boxes1`` has an integer dtype, the result is returned as ``torch.float32``. |
| 943 | |
| 944 | Reference: |
| 945 | https://giou.stanford.edu/GIoU.pdf |
| 946 | |
| 947 | """ |
| 948 | |
| 949 | if not isinstance(boxes1, type(boxes2)): |
| 950 | warnings.warn(f"boxes1 is {type(boxes1)}, while boxes2 is {type(boxes2)}. The result will be {type(boxes1)}.") |
| 951 | |
| 952 | # convert numpy to tensor if needed |
| 953 | boxes1_t, *_ = convert_data_type(boxes1, torch.Tensor) |
| 954 | boxes2_t, *_ = convert_data_type(boxes2, torch.Tensor) |
| 955 | |
| 956 | if boxes1_t.shape != boxes2_t.shape: |
| 957 | raise ValueError("boxes1 and boxes2 should be paired and have same shape.") |
| 958 | |
| 959 | spatial_dims = get_spatial_dims(boxes=boxes1_t) |
| 960 | |
| 961 | # we do computation with compute_dtype to avoid overflow |
| 962 | box_dtype = boxes1_t.dtype |
| 963 | |
| 964 | # compute area |
| 965 | area1 = box_area(boxes=boxes1_t.to(dtype=COMPUTE_DTYPE)) # (N,) |
| 966 | area2 = box_area(boxes=boxes2_t.to(dtype=COMPUTE_DTYPE)) # (N,) |
| 967 | |
| 968 | # Intersection |
| 969 | # get the left top and right bottom points for the boxes pair |
| 970 | lt = torch.max(boxes1_t[:, :spatial_dims], boxes2_t[:, :spatial_dims]).to( |
| 971 | dtype=COMPUTE_DTYPE |
| 972 | ) # (N,spatial_dims) left top |
| 973 | rb = torch.min(boxes1_t[:, spatial_dims:], boxes2_t[:, spatial_dims:]).to( |
| 974 | dtype=COMPUTE_DTYPE |
| 975 | ) # (N,spatial_dims) right bottom |
| 976 | |
| 977 | # compute size for the intersection region for the boxes pair |
| 978 | wh = (rb - lt + TO_REMOVE).clamp(min=0) # (N,spatial_dims) |
| 979 | inter = torch.prod(wh, dim=-1, keepdim=False) # (N,) |
| 980 | |
| 981 | # compute IoU and convert back to original box_dtype |
| 982 | union = area1 + area2 - inter |
| 983 | iou = inter / (union + torch.finfo(COMPUTE_DTYPE).eps) # (N,) |
| 984 |
searching dependent graphs…