- Published on
行为检测系统中的 IOU 计算
IoU 是 Intersection over Union(交并比)的缩写,是目标检测、语义分割等计算机视觉任务中最常用的评估指标,用于衡量预测结果与真实结果的重叠程度。
📐 定义
IoU 计算的是 预测框 与 真实框 的 交集面积 与 并集面积 的比值:
IoU = (A ∩ B) / (A ∪ B)
其中:
- A ∩ B(交集):两个框重叠部分的面积
- A ∪ B(并集):两个框覆盖的总面积
🎯 取值范围
| IoU 值 | 含义 |
|---|---|
| 1.0 | 完全重合(完美预测) |
| 0.5 ~ 0.9 | 有不同程度的重叠(通常可接受) |
| 0.0 | 完全不相交 |
| > 0.5 | 通常认为检测有效(常见阈值) |
📊 图解示例
真实框 (A) 预测框 (B) 交集 (A∩B) 并集 (A∪B)
┌─────┐ ┌─────┐ ┌─┐ ┌─────┐
│ │ │ │ │ │ │ │
│ A │ │ B │ │ │ (重叠区域) │ A∪B │
│ │ │ │ │ │ │ │
└─────┘ └─────┘ └─┘ └─────┘
IoU = 交集面积 / 并集面积 = 重叠部分 / (A面积 + B面积 - 重叠部分)
💻 代码实现
Python 版本(最常用)
def calculate_iou(box1, box2):
"""
计算两个边界框的 IoU
Args:
box1, box2: [x1, y1, x2, y2] 格式,左上角和右下角坐标
"""
# 计算交集坐标
x1 = max(box1[0], box2[0])
y1 = max(box1[1], box2[1])
x2 = min(box1[2], box2[2])
y2 = min(box1[3], box2[3])
# 计算交集面积(如果没有重叠则为0)
intersection = max(0, x2 - x1) * max(0, y2 - y1)
# 计算各自面积
area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
# 计算并集面积
union = area1 + area2 - intersection
# 返回 IoU
return intersection / union if union > 0 else 0
# 示例
pred = [50, 50, 150, 150] # 预测框
truth = [60, 60, 140, 140] # 真实框
iou = calculate_iou(pred, truth)
print(f"IoU: {iou:.3f}") # 输出: IoU: 0.640
Rust 版本(匹配你的项目)
#[derive(Debug, Clone, Copy)]
struct BBox {
x1: f32,
y1: f32,
x2: f32,
y2: f32,
}
impl BBox {
fn area(&self) -> f32 {
(self.x2 - self.x1) * (self.y2 - self.y1)
}
fn intersection(&self, other: &Self) -> f32 {
let x1 = self.x1.max(other.x1);
let y1 = self.y1.max(other.y1);
let x2 = self.x2.min(other.x2);
let y2 = self.y2.min(other.y2);
if x2 > x1 && y2 > y1 {
(x2 - x1) * (y2 - y1)
} else {
0.0
}
}
fn iou(&self, other: &Self) -> f32 {
let inter = self.intersection(other);
let union = self.area() + other.area() - inter;
if union > 0.0 {
inter / union
} else {
0.0
}
}
}
🎯 常见应用场景
1. 目标检测
判断检测是否正确:当 IoU > 0.5 时,通常认为检测到了目标
真实框: [狗]
预测框: [狗] → IoU = 0.75 ✅ 正确检测
预测框: [猫] → IoU = 0.12 ❌ 错误检测
2. 模型评估(mAP)
mAP(mean Average Precision)依赖 IoU 阈值:
- IoU=0.5:标准 PASCAL VOC 指标
- IoU=0.5:0.95:COCO 数据集的严格指标(多个阈值平均)
3. 非极大值抑制(NMS)
去除重复检测框:当两个框的 IoU > 阈值(如 0.5),保留置信度高的
# NMS 伪代码
for box in boxes:
if any(calculate_iou(box, kept_box) > 0.5 for kept_box in kept):
skip # 重复检测,跳过
else:
keep(box) # 保留这个检测
4. 跟踪算法(如你的项目)
关联检测结果与轨迹:计算当前帧检测框与历史轨迹的 IoU,确定是否匹配
// 匹配检测结果与跟踪目标
fn match_detections_to_tracks(
detections: &[BBox],
tracks: &[Track]
) -> Vec<Match> {
let mut iou_matrix = vec![vec![0.0; tracks.len()]; detections.len()];
for (i, det) in detections.iter().enumerate() {
for (j, track) in tracks.iter().enumerate() {
iou_matrix[i][j] = det.iou(&track.bbox);
}
}
// 匈牙利算法匹配,IoU > 0.3 认为有效
hungarian_matching(&iou_matrix, 0.3)
}
📈 不同 IoU 阈值的效果
| IoU 阈值 | 宽松度 | 用途 |
|---|---|---|
| 0.3 | 很宽松 | 目标跟踪(允许漂移) |
| 0.5 | 标准 | 一般目标检测评估 |
| 0.7 | 严格 | 高精度检测(人脸、OCR) |
| 0.9 | 非常严格 | 实例分割、像素级检测 |
⚠️ 注意事项
- 框的格式:确保坐标格式一致(
xyxy、xywh、cxcywh等) - 归一化坐标:检查是否归一化到 [0,1] 还是绝对像素值
- 空框处理:注意除以 0 的情况(当 union = 0 时)
THE END