lilanxiao / Rotated_IoU

Differentiable IoU of rotated bounding boxes using Pytorch
MIT License
415 stars 64 forks source link

Wrong IoU calculation when corners are smaller than 0 #40

Open Eralien opened 2 years ago

Eralien commented 2 years ago

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 commented 2 years ago

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.

rubbish001 commented 2 years ago

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

lilanxiao commented 2 years ago

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.

Eralien commented 2 years ago

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.

rubbish001 commented 2 years ago

还是会出现nan

xiazhiyi99 commented 1 year ago

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.