Rotated_IoU icon indicating copy to clipboard operation
Rotated_IoU copied to clipboard

Wrong IoU calculation when corners are smaller than 0

Open Eralien opened this issue 2 years ago • 6 comments

Hi! Thank you @lilanxiao for your great work. I have been using your work for sometime, and it has been beneficial for my training.

One problem I encountered was under certain circumstances, the IoU calculations are wrong. Most of them happened when the calculated corners of boxes are smaller than zero. Some happened when length or width are too small, which may have something to do with numeric instability. There's maybe other cases, but these two are what I have discovered.

My environment: Ubuntu 18.04, CUDA 11.2, Pytorch 1.8, python 3.8

Eralien avatar Apr 08 '22 11:04 Eralien

I have a simple solution for the corners problem: simply add a translation to all boxes if any of their corners coordinates is negative.

def cal_iou(box1: torch.Tensor, box2: torch.Tensor):
    """calculate iou
    Args:
        box1 (torch.Tensor): (B, N, 5) with x, y, w, h, alpha
        box2 (torch.Tensor): (B, N, 5) with x, y, w, h, alpha

    Returns:
        iou (torch.Tensor): (B, N)
        corners1 (torch.Tensor): (B, N, 4, 2)
        corners1 (torch.Tensor): (B, N, 4, 2)
        U (torch.Tensor): (B, N) area1 + area2 - inter_area
    """
    corners1 = box2corners_th(box1)
    corners2 = box2corners_th(box2)

    # calculate the min corner coordinates
    corners_min = torch.minimum(corners1, corners2).amin(-2) - 1e-5   # eps
    # if any element is negative, translate all coordinates to positive number
    if corners_min.lt(0).any():
        corners1_positive = corners1 - corners_min
        corners2_positive = corners2 - corners_min
        inter_area, _ = oriented_box_intersection_2d(corners1_positive, corners2_positive)    # (B, N)
    else:
        # if not, directly calculate the intersection area
        inter_area, _ = oriented_box_intersection_2d(corners1, corners2)    # (B, N)
    area1 = box1[:, :, 2] * box1[:, :, 3]
    area2 = box2[:, :, 2] * box2[:, :, 3]
    u = area1 + area2 - inter_area
    iou = inter_area / u
    return iou, corners1, corners2, u

I tested the results against the one implemented in detectron2, and the results difference for 1000 random tests are within 1e-3.

Eralien avatar Apr 08 '22 12:04 Eralien

代码有问题,不知道怎么改,求作者更新代码

rubbish001 avatar Apr 22 '22 08:04 rubbish001

hi, thank you for the issue and workaround. I've just updated my code in the debug branch. I think the new version is probably more stable. Please let me know if the problem persists.

lilanxiao avatar Jun 03 '22 20:06 lilanxiao

hi, thank you for the issue and workaround. I've just updated my code in the debug branch. I think the new version is probably more stable. Please let me know if the problem persists.

Thanks! Will test soon.

Eralien avatar Jun 14 '22 06:06 Eralien

还是会出现nan

rubbish001 avatar Jun 15 '22 07:06 rubbish001

same problem Can we simply add a constant big value to the corners at the beginning like this?

def cal_iou(box1:Tensor, box2:Tensor):
    corners1 = box2corners_th(box1) + 100
    corners2 = box2corners_th(box2) + 100
    ...

I tried it and it seems fine.

xiazhiyi99 avatar Aug 03 '23 18:08 xiazhiyi99