昨天深夜调试时遇到一个诡异问题:模型在测试集上mAP挺漂亮,但实际部署到游戏画面里,检测框总是飘忽不定,时而套住怪物,时而框住背景里的树枝。熬到凌晨三点才发现,原来YOLO输出的坐标格式和游戏屏幕坐标系根本对不上。今天咱们就彻底拆解这个环节——目标检测结果解析,这是模型落地最关键也最容易踩坑的一步。
## 一、YOLO输出到底长什么样?
拿YOLOv5举例,模型原始输出是个形状为`[1, 25200, 85]`的张量(以640x640输入为例)。这个25200是哪来的?其实是三个检测层网格数的总和:80x80 + 40x40 + 20x20 = 25200。每个预测框包含85个值:前4个是坐标和尺寸,第5个是框内存在物体的置信度,后80个是COCO数据集的类别概率。
```python
# 原始输出示例 - 别直接拿来用!
raw_output = model(frame) # 形状 [1, 25200, 85]
# 第一个预测框的数据结构:
# [x_center, y_center, width, height, obj_conf, class1_prob, class2_prob, ...]
```
这里第一个坑:这些坐标都是归一化值,相对于输入图像的尺寸。如果你用640x640训练,但推理时传入1280x720的画面,不转换坐标直接画框,结果肯定错位。
## 二、坐标转换:从归一化到屏幕像素
坐标转换分两步走,缺一不可。第一步把归一化坐标转回模型输入尺寸下的像素坐标,第二步再映射到原始屏幕分辨率。
```python
def yolo_to_pixel(bbox, input_size=(640, 640), screen_size=(1920, 1080)):
"""
bbox: [x_center_norm, y_center_norm, width_norm, height_norm]
返回: (x1, y1, x2, y2) 屏幕像素坐标
"""
# 第一步:转到模型输入尺寸下的像素坐标
x_center = bbox[0] * input_size[0]
y_center = bbox[1] * input_size[1]
width = bbox[2] * input_size[0]
height = bbox[3] * input_size[1]
# 计算左上角和右下角(YOLO存的是中心点+宽高)
x1 = x_center - width / 2
y1 = y_center - height / 2
x2 = x_center + width / 2
y2 = y_center + height / 2
# 第二步:缩放到实际屏幕尺寸
# 注意!这里假设模型输入时保持了宽高比进行填充,实际情况更复杂
scale_x = screen_size[0] / input_size[0]
scale_y = screen_size[1] / input_size[1]
# 如果推理时用了letterbox(保持宽高比的填充),
# 还需要考虑填充的黑边,这里简化处理,实际项目要记录填充参数
x1, x2 = x1 * scale_x, x2 * scale_x
y1, y2 = y1 * scale_y, y2 * scale_y
return int(x1), int(y1), int(x2), int(y2)
```
重点来了:如果你在预处理时用了`letterbox`(保持宽高比的填充),转换时必须考虑填充的偏移量。我吃过这个亏——检测框整体偏移了30像素,就是因为忘了加回`pad_x`和`pad_y`。
## 三、置信度筛选:别只看阈值
新手常犯的错误:设置一个固定置信度阈值,比如0.5,然后全盘接收高于这个值的预测框。结果就是重复检测——同一个怪物身上套着三四个框。
```python
# 典型错误示范 - 别这样写!
conf_threshold = 0.5
high_c
2043



被折叠的 条评论
为什么被折叠?



