`pred_by_img.setdefault(img, [ ]).append({...})`
pred_by_img.setdefault(img, [ ]).append({...})
这一句的核心目的是 把同一张图片的全部预测框归档到同一个列表里,后面做 IoU 匹配就能 O(1)
取出。
为啥要这样分组?
-
遍历标签时,只关心当前这张图的预测
PR = pred_by_img.get(img_name, [])
如果不用字典分组,得在几万条预测里反复筛选,效率极低。
-
字典键 = 图片名
- 一张图只会出现一次键
setdefault
:第一次遇到这张图时自动建空列表;以后直接追加
存进去的两项字段
{"cls": p["category_id"] - 1, # ① 预测类别(1‑12) → 0‑11 与 GT 对齐"box": [x1, y1, x2, y2] # ② bbox 从 (x, y, w, h) → (x1, y1, x2, y2)
}
字段 | 为什么要转? |
---|---|
cls | GT 的类别是 0‑11,而 predictions.json 给的是 1‑12;减 1 才能写进同一个混淆矩阵行/列。 |
box | IoU 计算函数用 左上+右下 格式 (x1,y1,x2,y2) ;YOLO 预测给的是 (x,y,w,h) 。所以提前转换,后面直接算 IoU。 |
小示例
假设 predictions.json
里有三条记录:
image_id | category_id | bbox (xywh) | score |
---|---|---|---|
imgA | 11 | [100,200,50,80] | 0.8 |
imgA | 12 | [300,100,40,40] | 0.7 |
imgB | 10 | [120,220,60,70] | 0.9 |
执行循环后,pred_by_img
结构:
{"imgA.jpg": [{"cls": 10, "box": [100,200,150,280]}, # 11‑1 → 10{"cls": 11, "box": [300,100,340,140]}],"imgB.jpg": [{"cls": 9, "box": [120,220,180,290]}]
}
- 取
pred_by_img["imgA.jpg"]
就直接拿到 imgA 的 2 个预测框 - 后面做 一对一匹配 时非常高效
一句话总结
用
pred_by_img
“按图索引” 所有预测框,
同时把 类别编号和坐标格式预处理好,
这样在主循环里对每张图做 IoU 匹配时既快又少出错。