了解目标检测
读取检测器的输出——类别、边界框、置信度——并根据不同错误的代价设定置信度和 IoU 阈值。
大多数生产环境中的视觉系统都是在检测基础上叠加逻辑:计数器、跟踪器、区域告警、隐私模糊处理。系统出问题时,原因通常不是模型,而是没人认真设定过某个阈值。了解检测器究竟会返回什么,以及哪两个参数会影响结果列表,你就能调试几乎所有基于检测构建的功能。
实践操作
检测器会返回什么#

图像中的每个标签都对应一行输出:类别名称、置信度,以及对象周围的边界框。检测模型返回的正是这样的列表:
- 类别 — 一个整数索引,通过
result.names映射到名称(0是person,5是bus)。 - 边界框 — 用于定位对象的四个数值;
xyxy用像素坐标给出左上角和右下角。 - 置信度 — 一个 0 到 1 之间的分数,用于为检测结果排序和筛选。
计数、告警、跟踪和模糊处理,都是你基于这些输出行编写的代码。
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]
for box in result.boxes:
name = result.names[int(box.cls)]
x1, y1, x2, y2 = box.xyxy[0].tolist()
print(f"{name:8} conf={float(box.conf):.2f} box=({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f})")bus conf=0.88 box=(0, 230, 803, 751)
person conf=0.87 box=(49, 398, 240, 902)
person conf=0.86 box=(223, 405, 345, 861)
person conf=0.85 box=(670, 395, 810, 880)
person conf=0.65 box=(0, 553, 60, 871)逐行来看:公交车的边界框从 x=0 开始,因为公交车从左侧边缘延伸出画面;三名行人的置信度为 0.85–0.87;第四名行人被左侧边缘截断,置信度只有 0.65——模型只能看到半个身体。被截断对象的置信度偏低很正常,而它也是最先受到阈值影响的情况。
每个边界框都可以采用四种格式;根据下游代码的需求选择:
| 属性 | 格式 | 典型用途 |
|---|---|---|
boxes.xyxy | 角点像素坐标 (x1, y1, x2, y2) | 裁剪、绘制、重叠规则 |
boxes.xywh | 中心像素坐标加宽度和高度 | 尺寸筛选、运动分析 |
boxes.xyxyn | 归一化到 0–1 的角点坐标 | 适用于不同分辨率的规则 |
boxes.xywhn | 归一化到 0–1 的中心坐标和尺寸 | YOLO 标签文件 |
从候选框到最终列表#
模型内部会为每个对象评估许多候选边界框。经过两种筛选后,才会得到你看到的列表:
置信度筛选。 conf 会过滤掉低于阈值的边界框;预测时的默认阈值为 0.25。对于公交车图像,数量会很快发生变化:
conf | bus.jpg 上的边界框 |
|---|---|
| 0.10 | 7 |
| 0.25 | 5 |
| 0.50 | 5 |
| 0.75 | 4 |
重复项筛选。非极大值抑制 (NMS) 会保留置信度最高的边界框,并删除同类别中与它的重叠程度超过 iou(默认值为 0.7)的其他边界框。重叠程度通过交并比衡量:共享区域面积除以合并后的总面积。

iou | bus.jpg 上的边界框 | 效果 |
|---|---|---|
| 0.3 | 5 | 严格:重叠框会被合并 |
| 0.7 | 5 | 默认 |
| 0.95 | 8 | 宽松:近似重复项会保留 |
根据错误的代价选择阈值#
| 如果…… | 那么…… |
|---|---|
| 漏检代价很高(安全警报、缺陷) | 降低 conf,并接受一些误报 |
| 误报会被用户看到(搜索、标记) | 提高 conf |
| 你要报告计数 | 在验证图像上遍历 conf,并选择计数误差最小的值 |
| 拥挤场景中的真实相邻目标会消失 | 提高 iou,例如从 0.7 提高到 0.8 |
| 同一个目标被框出两次 | 降低 iou |
| 不同类别的难度各不相同 | 使用所需的最低 conf 进行预测,然后在代码中按类别筛选 |
仓库安全监控是典型的低阈值场景;预测模式列出了所有推理参数。
常见问题#
症状:“模型有 88% 的把握认为这是公交车”,并凭直觉选择阈值。解决方法:将置信度视为排序分数。在 YOLO26 中,一个分数同时表示“存在一个物体”和“它属于这个类别”,而且这个分数未经校准——应根据验证数据选择阈值,而不是根据数值的字面含义。
两个人肩并肩站着时,他们的边界框会高度重叠,NMS 可能会把真实的人当作“重复项”删除。调高 iou,第二个边界框就会恢复。YOLO26 还提供了无需 NMS 的端到端检测头;传入 nms=False 即可使用。
症状:某个阈值在演示图像上看起来完美,到了真实摄像头画面中却失效。解决方法:在来自部署摄像头的验证集上扫描阈值;一张图像只能让你了解各参数的作用。
四种出错方式#
| 失败情况 | 哪里出了问题 | 典型修复方法 |
|---|---|---|
| 类别正确,框不准 | 定位 | 统一并收紧框选规则;对小目标使用更大的 imgsz |
| 框正确,类别错误 | 分类 | 增加易混淆类别对的样本,或合并这些类别 |
| 完全没有框 | 召回率 | 增加该情况的样本:光照、尺寸、遮挡 |
| 在背景上出现框 | 精确率 | 加入容易误导模型的对象的困难负样本图像 |
两份列表可以快速诊断问题:低置信度的真正例(模型不确定真实目标是否存在)和高置信度的假正例(模型确信地识别错了)。它们对应不同的修复方法。
显示解答
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", conf=0.05, save=True, verbose=False)[0]
for box in sorted(result.boxes, key=lambda b: -float(b.conf)):
name, conf = result.names[int(box.cls)], float(box.conf)
x1, y1, x2, y2 = box.xyxy[0].tolist()
print(f"{conf:.2f} {name:10} ({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f})")0.88 bus (0, 230, 803, 751)
0.87 person (49, 398, 240, 902)
0.86 person (223, 405, 345, 861)
0.85 person (670, 395, 810, 880)
0.65 person (0, 553, 60, 871)
0.18 person (0, 600, 40, 871)
0.12 stop sign (0, 252, 35, 326)
0.08 handbag (43, 732, 78, 812)
0.07 skateboard (669, 822, 808, 881)
0.06 handbag (225, 634, 291, 705)所有低于 0.5 的框都是假正例。0.18 的 person 与左边缘被截断、置信度为 0.65 的行人重复。0.12 的 stop sign 是一块真实路牌,但类别错误。手提包和滑板实际框到了手和鞋子。所有真实目标的得分都高于 0.6,因此对于行人计数器,conf=0.5 会保留全部四个人并去除所有干扰项,从而防止重复计数。部署前,请用真实摄像头的验证集确认这一点:置信度为 0.65 的截断行人表明,真实目标的得分可能会非常接近阈值。