标准回答
IoU(交并比)衡量两个边界框的重叠程度,是目标检测里 NMS 和 mAP 评估的核心。计算分三步:先求交集矩形(左上取两框左上坐标的逐分量最大值,右下取右下坐标的最小值),交集宽高务必用 max(0,...) 钳制以处理不相交情形;再用容斥求并集面积;最后相除。下面给出单框版与向量化批量版:
python
import numpy as np
def iou(box_a, box_b):
"""框格式 [x1, y1, x2, y2](左上、右下)。"""
# 交集矩形的左上与右下
x1 = max(box_a[0], box_b[0])
y1 = max(box_a[1], box_b[1])
x2 = min(box_a[2], box_b[2])
y2 = min(box_a[3], box_b[3])
# 无重叠时宽/高为负,钳制到 0
inter = max(0, x2 - x1) * max(0, y2 - y1)
area_a = (box_a[2] - box_a[0]) * (box_a[3] - box_a[1])
area_b = (box_b[2] - box_b[0]) * (box_b[3] - box_b[1])
union = area_a + area_b - inter
return inter / union if union > 0 else 0.0
def iou_matrix(boxes_a, boxes_b):
"""向量化:boxes_a (N,4), boxes_b (M,4) -> IoU 矩阵 (N, M)。"""
a = np.asarray(boxes_a, dtype=float)
b = np.asarray(boxes_b, dtype=float)
x1 = np.maximum(a[:, None, 0], b[None, :, 0])
y1 = np.maximum(a[:, None, 1], b[None, :, 1])
x2 = np.minimum(a[:, None, 2], b[None, :, 2])
y2 = np.minimum(a[:, None, 3], b[None, :, 3])
inter = np.clip(x2 - x1, 0, None) * np.clip(y2 - y1, 0, None)
area_a = (a[:, 2] - a[:, 0]) * (a[:, 3] - a[:, 1])
area_b = (b[:, 2] - b[:, 0]) * (b[:, 3] - b[:, 1])
union = area_a[:, None] + area_b[None, :] - inter
return np.where(union > 0, inter / union, 0.0)
if __name__ == '__main__':
print(round(iou([0, 0, 2, 2], [1, 1, 3, 3]), 4)) # 1/7 ≈ 0.1429
print(round(iou([0, 0, 1, 1], [2, 2, 3, 3]), 4)) # 不相交 -> 0.0
print(np.round(iou_matrix([[0, 0, 2, 2]], [[1, 1, 3, 3], [0, 0, 2, 2]]), 4))常见误区
⚠️ 常见踩坑
忘记对交集宽高做 max(0,...) 钳制,两框不相交时算出负宽乘负高变成正面积,IoU 完全错误。另一坑是坐标约定:[x,y,w,h] 与 [x1,y1,x2,y2] 不可混用,需先统一转换;并集为 0(退化框)时要返回 0 防除零。
追问
追问 1:IoU 在 NMS 里如何使用?复杂度?
NMS 先按置信度排序,保留最高分框,剔除与它 IoU 超过阈值(如 0.5)的其余框,循环往复。朴素实现 O(n²),n 为候选框数。改进有 Soft-NMS(按 IoU 衰减分数而非硬删)和向量化批量计算 IoU 矩阵加速。
追问 2:IoU 作为损失有什么问题,GIoU/DIoU 怎么改进?
两框不相交时 IoU 恒为 0、梯度消失,无法指导回归靠近。GIoU 引入最小包围框惩罚分离程度;DIoU 进一步加入中心点距离项加速收敛;CIoU 再考虑长宽比一致性,使边界框回归更稳更快。
延伸学习
与本题相关的知识库文章、术语、工具与行业资讯。