1. Description
IoU loss is the most common loss function in target detection, which represents the intersection ratio of the real box and the predicted box.
2. Code implementation
import math
def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
# Returns Intersection over Union IoU(n,1) of box1(n,4) to box2(n,4)
# Get the coordinates of bounding boxes
if xywh: # transform from xywh to xyxy
x1, y1, w1, h1 = box1.chunk(4, -1) # n*4 --> n*1, n*1, n*1, n*1
x2, y2, w2, h2 = box2.chunk(4, -1)
b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1 / 2, x1 + w1 / 2, y1 - h1 / 2, y1 + h1 / 2
b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2 / 2, x2 + w2 / 2, y2 - h2 / 2, y2 + h2 / 2
else: # x1, y1, x2, y2 = box
b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1) # n*4 --> n*1, n*1, n*1, n*1
b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
# Intersection Area n*1
inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * \
(b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp(0)
# Union Area n*1
union = w1 * h1 + w2 * h2 - inter + eps
# IoU n*1
iou = inter / union
if CIoU or DIoU or GIoU:
cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1) # convex width
ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1) # convex height
if CIoU or DIoU: # Distance or Complete IoU
c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2
if CIoU:
v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)
with torch.no_grad():
alpha = v / (v - iou + (1 + eps))
return iou - (rho2 / c2 + v * alpha) # CIoU = IoU - center_dist / diagonal_dist - length_width_ratio
return iou - rho2 / c2 # DIoU = IoU - center_dist / diagonal_dist
c_area = cw * ch + eps # convex area
return iou - (c_area - union) / c_area # GIoU = IoU - (area_convex - area_union) / area_convex
return iou # IoU