3. 目标检测基础回顾:YOLOv5/v8原理简介、使用预训练模型进行行人/车辆检测、检测结果格式

好,咱们进入第三讲。做多目标跟踪,说白了,你得先能「看见」目标。这个「看见」的活儿,就是目标检测干的。我见过不少新手,一上来就调跟踪参数,结果发现检测框满天飞——那跟踪效果能好才怪。所以,今天咱们把检测这块地基夯实了。

3.1 YOLOv5与YOLOv8:两代经典,各有千秋

YOLO系列,全称You Only Look Once。意思就是「看一眼就够了」。它不像老派的Faster R-CNN那样分两步走,而是把目标检测当成一个回归问题,一步到位输出边界框和类别。我个人习惯把YOLO理解为「用整张图做一次前向推理,直接告诉你哪里有什么」。

3.1.1 YOLOv5:稳定可靠的老伙计

YOLOv5虽然名字里带个v5,但它其实不是官方YOLO作者的作品,而是Ultralytics团队搞的。不过这不重要,好用就行。我在项目中遇到过很多次,YOLOv5在中等算力的设备上(比如Jetson Nano)跑得飞起,精度也够用。

它的核心结构可以拆成三块:

  • Backbone(骨干网络):用CSPDarknet53提取特征。说白了就是一堆卷积堆叠,把图片变成特征图。
  • Neck(颈部):用FPN+PAN结构做特征融合。小目标用大特征图,大目标用小特征图,各取所需。
  • Head(检测头):输出三个尺度的预测结果。每个尺度负责检测不同大小的物体。

关键点:YOLOv5的损失函数包含三部分——框回归损失(CIoU)、置信度损失(BCE)、分类损失(BCE)。训练时这三者加权求和,权重比例我一般用0.05:1.0:0.5,效果比较稳。

3.1.2 YOLOv8:新秀登场,更丝滑

YOLOv8是Ultralytics在2023年初推出的。相比v5,它做了几个重要改进:

  • 无锚框检测(Anchor-Free):v5需要预设一堆锚框,v8直接预测中心点和宽高。你想想看,少了一个调参的烦恼。
  • C2f模块:取代了v5的C3模块。梯度流更丰富,特征表达能力更强。
  • 解耦检测头:分类和回归用不同的卷积分支。我试过,收敛速度确实快一些。

嗯,这里要注意:v8的模型体积比v5稍大,但推理速度几乎没差。如果你在边缘设备上跑,v5可能更省心;如果追求极致精度,v8是更好的选择。

对比项 YOLOv5 YOLOv8
锚框机制 有锚框(Anchor-Based) 无锚框(Anchor-Free)
骨干网络 CSPDarknet53 改进版CSPDarknet + C2f
检测头 耦合头 解耦头
推理速度 稍快 几乎持平
mAP精度 良好 略高(约1-2%)

3.2 使用预训练模型进行行人/车辆检测

讲完原理,咱们直接上手。我建议你直接用Ultralytics的官方库,几行代码就能跑起来。别自己从头训练,除非你有几十万张标注图——我曾经试过自己标了5000张,效果还不如人家预训练的零头。

3.2.1 安装与加载模型

pip install ultralytics

装好之后,加载模型就这么简单:

from ultralytics import YOLO

# 加载YOLOv8预训练模型(自动下载权重)
model = YOLO('yolov8n.pt')  # n: nano版本,最快但精度最低
# 或者用YOLOv5
# model = YOLO('yolov5su.pt')

这里有个小技巧:如果你只检测行人和车辆,可以指定类别过滤,省掉不必要的计算。

3.2.2 对图片进行检测

results = model('street.jpg')  # 传入图片路径

# 遍历检测结果
for result in results:
    boxes = result.boxes  # 边界框对象
    for box in boxes:
        x1, y1, x2, y2 = box.xyxy[0].tolist()  # 左上角+右下角坐标
        conf = box.conf[0].item()               # 置信度
        cls = int(box.cls[0].item())            # 类别ID
        
        # COCO数据集中:0=人, 2=汽车, 3=摩托车, 5=公交车, 7=卡车
        if cls in [0, 2, 5, 7]:  # 只保留行人和车辆
            print(f'检测到目标: 类别{cls}, 置信度{conf:.2f}, 坐标({x1:.0f},{y1:.0f},{x2:.0f},{y2:.0f})')

我的经验:实际项目中,置信度阈值别设太低。我一般设0.5以上。低于0.5的框,十有八九是误检。尤其是行人,树影、垃圾桶都容易误报。

3.2.3 对视频流进行检测

做多目标跟踪,你肯定要处理视频。YOLO对视频的处理也很直接:

results = model('traffic.mp4', stream=True)  # stream=True表示流式处理

for frame_idx, result in enumerate(results):
    # 每帧的检测结果
    boxes = result.boxes
    # ... 处理逻辑同上
    if frame_idx % 30 == 0:
        print(f'已处理 {frame_idx} 帧')

为什么会用stream=True?因为如果不加,它会等所有帧处理完才返回结果,内存直接爆炸。我刚开始就吃过这个亏,处理一段10分钟的视频,内存飙到16G——嗯,从那以后我再也不敢忘了这个参数。

3.3 检测结果格式详解

检测结果说白了就是三样东西:边界框(bbox)置信度(confidence)类别(class)。这三者缺一不可,是后续跟踪算法的输入。

3.3.1 边界框格式

YOLO输出两种常见的框格式:

  • xyxy格式[x1, y1, x2, y2],左上角和右下角坐标。直观,但框的宽高需要自己算。
  • xywh格式[x_center, y_center, width, height],中心点+宽高。SORT和DeepSORT内部常用这种。

转换很简单:

# xyxy -> xywh
x_center = (x1 + x2) / 2
y_center = (y1 + y2) / 2
width = x2 - x1
height = y2 - y1

# xywh -> xyxy
x1 = x_center - width / 2
y1 = y_center - height / 2
x2 = x_center + width / 2
y2 = y_center + height / 2

注意:坐标都是归一化到[0,1]之间的吗?不一定。YOLOv5/v8默认输出的是像素坐标(绝对坐标),除非你指定了normalized=True。做跟踪时,我建议统一用像素坐标,因为卡尔曼滤波需要绝对位置信息。

3.3.2 置信度与类别

置信度是一个0到1之间的浮点数,表示模型对这个框的「自信程度」。类别是整数ID,对应COCO数据集的80个类别。咱们做行人/车辆检测,重点关注这几个:

类别ID 名称 说明
0 person 行人,跟踪的核心目标
2 car 小轿车,常见
5 bus 公交车,体积大
7 truck 卡车,注意和bus区分

3.3.3 完整的检测结果结构

在Ultralytics中,一个检测结果通常组织成这样的数据结构:

# 假设当前帧检测到3个目标
detections = [
    {
        'bbox': [100, 200, 150, 350],  # xyxy格式,像素坐标
        'confidence': 0.92,
        'class_id': 0,                  # 行人
        'class_name': 'person'
    },
    {
        'bbox': [300, 250, 450, 400],
        'confidence': 0.88,
        'class_id': 2,                  # 汽车
        'class_name': 'car'
    },
    {
        'bbox': [500, 300, 600, 420],
        'confidence': 0.45,             # 置信度低,建议过滤
        'class_id': 0,
        'class_name': 'person'
    }
]

# 过滤低置信度检测
valid_detections = [d for d in detections if d['confidence'] > 0.5]
print(f'有效检测数: {len(valid_detections)}')

避坑指南:我曾经在跟踪时直接把所有检测结果喂给SORT,结果发现跟踪器频繁切换ID。后来排查发现,是那些置信度0.3左右的误检框在捣乱。所以,检测质量直接决定跟踪上限。宁可漏检,不要误检。

3.4 小结

这一章咱们把目标检测的基础过了一遍。YOLOv5和v8各有优势,选哪个看你自己的场景。预训练模型直接拿来用,省时省力。检测结果格式要记牢——bbox、confidence、class,这三个字段是后续所有跟踪算法的输入。

下一章,咱们就要正式进入SORT算法的核心了。到时候你会发现,检测做得越扎实,跟踪调参就越轻松。嗯,咱们下节课见。