YOLO 推理输出结构
标准 YOLO API 输出格式(以 Ultralytics 为例):
{
"class": "vehicle",
"class_id": 1,
"confidence": 0.91,
"bbox": {
"x1": 156.15, "y1": 487.68,
"x2": 653.12, "y2": 690.16,
"width": 496.97, "height": 202.47
}
}
判断结果质量时关注两点:
- 置信度分布:主要目标是否集中在 0.7 以上
- 框的空间分布:是否存在高度重叠的框
四类常见问题
1. 重复框(NMS 不净)
同一辆车被检测 2~3 次,框坐标相近但不完全重合。原因是 IOU 阈值偏低,NMS 未能合并相似框。
# 默认 0.45 偏低,调高到 0.55~0.60
results = model(img, iou=0.55)
2. 低置信度噪声
大量 confidence < 0.4 的框混入结果,尤其是行人、远处小目标。默认 conf=0.25 会保留大量噪声。
# 推荐生产阈值
results = model(img, conf=0.45)
效果:去掉垃圾框,结果更干净,后续处理负担更小。
3. 小目标识别差
行人、远处目标置信度普遍偏低(< 0.5),框也不稳定。可能的原因:
- 输入分辨率不够(模型内部将图缩放到 640×640 后,远处目标只占几个像素)
- 训练数据中远距离目标样本少
优化方向:
# 提高推理分辨率
results = model(img, imgsz=1280)
或使用更适合小目标的模型(yolo11x 或 RT-DETR)。
4. 类别冲突(person vs two_wheel)
人骑车时同时触发 person 框和 two_wheel 框,两框高度重叠。后处理规则:
def resolve_conflict(detections, iou_thresh=0.7):
persons = [d for d in detections if d["class"] == "person"]
bikes = [d for d in detections if d["class"] == "two_wheel"]
to_remove = set()
for p in persons:
for b in bikes:
if compute_iou(p["bbox"], b["bbox"]) > iou_thresh:
# 保留置信度高的
if p["confidence"] < b["confidence"]:
to_remove.add(id(p))
else:
to_remove.add(id(b))
return [d for d in detections if id(d) not in to_remove]
工程状态推荐参数
| 参数 | 实验值 | 推荐生产值 |
|---|---|---|
| conf_threshold | 0.25 | 0.45 |
| iou_threshold | 0.45 | 0.55 |
后处理 Pipeline
results = model(img, conf=0.45, iou=0.55)
detections = parse_results(results)
# 1. 过滤极小框(去远处误检)
detections = [d for d in detections
if d["bbox"]["width"] * d["bbox"]["height"] > min_area]
# 2. 类别冲突解决
detections = resolve_conflict(detections)
# 3. 业务逻辑处理
模型”能用”和”可上线”之间的差距主要就是以上这几个阈值和后处理步骤。
