Published on

行为检测系统中的 IOU 计算

IoUIntersection over Union(交并比)的缩写,是目标检测、语义分割等计算机视觉任务中最常用的评估指标,用于衡量预测结果与真实结果的重叠程度。

📐 定义

IoU 计算的是 预测框真实框交集面积并集面积 的比值:

IoU = (AB) / (AB)

其中:

  • A ∩ B(交集):两个框重叠部分的面积
  • A ∪ B(并集):两个框覆盖的总面积

🎯 取值范围

IoU 值含义
1.0完全重合(完美预测)
0.5 ~ 0.9有不同程度的重叠(通常可接受)
0.0完全不相交
> 0.5通常认为检测有效(常见阈值)

📊 图解示例

真实框 (A)         预测框 (B)         交集 (AB)         并集 (AB)
┌─────┐           ┌─────┐            ┌─┐                ┌─────┐
│     │           │     │            │ │                │     │
A  │           │  B  │            │   (重叠区域)AB│     │           │     │            │ │                │     │
└─────┘           └─────┘            └─┘                └─────┘

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非常严格实例分割、像素级检测

⚠️ 注意事项

  1. 框的格式:确保坐标格式一致(xyxyxywhcxcywh 等)
  2. 归一化坐标:检查是否归一化到 [0,1] 还是绝对像素值
  3. 空框处理:注意除以 0 的情况(当 union = 0 时)

THE END