DeepSORT:加入外观特征的深度多目标跟踪
DeepSORT 多目标跟踪:核心思想与架构
DeepSORT(Deep Simple Online and Realtime Tracking)是一种融合运动信息与外观特征的多目标跟踪算法。它在传统的 SORT 跟踪器基础上,引入深度卷积神经网络提取的外观描述子,以有效应对目标被长期遮挡或身份切换(ID Switch)的问题。本节将从问题定义出发,逐步拆解其关键模块。
多目标跟踪的通用框架
多目标跟踪(MOT)的目标是:在视频序列的每一帧中,定位出所有感兴趣的目标,并为每个目标分配一个唯一且稳定的身份标识(ID)。这等价于将跨帧的检测结果集关联为不同的轨迹。其核心挑战在于:
- 检测器的漏检与误检
- 目标间的相互遮挡与交叠
- 相似外观目标的混淆
- 目标进出场景导致轨迹的创建与终止
DeepSORT 的解决思路是将分配问题建模为:利用匈牙利算法对当前帧检测框与已存在轨迹的预测框进行匹配,匹配代价由运动模型和外观模型共同决定,并通过级联匹配机制优先关联近期活跃的轨迹。
SORT 的局限与外观特征的必要性
SORT 仅使用卡尔曼滤波预测的边界框 IoU 作为关联度量。当目标被短暂遮挡后重新出现,仅靠运动模型的预测位置往往有较大偏差,IoU 匹配容易失败,导致轨迹中断并分配新 ID,即频繁的身份切换。
DeepSORT 在保留 SORT 简洁高效特性的同时,加入深度外观描述向量,使跟踪器在运动信息不可靠时,能通过外观相似度找回原轨迹,显著降低 ID Switch。
运动状态估计与轨迹处理
DeepSORT 为每个目标维护一个 8 维状态空间:
x = [u, v, γ, h, ẋ, ẋ, γ̇, ḣ]
其中 (u, v) 是边界框中心坐标,γ 是宽高比,h 是高度,其余为对应速度分量。采用标准卡尔曼滤波器进行匀速运动和线性观测模型的预测与更新。
轨迹生命周期管理
每条轨迹拥有三个状态:
- 暂定(Tentative):新建轨迹,如果在接下来连续若干帧(默认 3 帧)内都能成功关联检测,则转为确定(Confirmed)。
- 确定(Confirmed):正常跟踪轨迹,可参与匹配。
- 删除(Deleted):若确定轨迹连续未匹配超过最大允许帧数(默认 30 帧),则视为目标已离开场景,轨迹被删除。
这种管理方式可避免噪声检测产生大量虚假轨迹,也保证了遮挡后仍有足够时间找回目标。
外观描述子的提取与使用
这是 DeepSORT 区别于 SORT 的核心模块。设计一个深度神经网络,将目标的图像块映射为一个固定长度的特征向量,并要求同一目标的不同视角/光照下的特征余弦距离尽量小,不同目标的余弦距离尽量大。
网络结构与训练策略
原文使用一个轻量级的宽残差网络(Wide Residual Network),在行人重识别(Person Re-Identification)数据集上进行训练。网络结构概览:
- 输入:缩放至 128×64 的 RGB 图像块
- 两个卷积层后接六个残差块
- 全连接层输出 128 维的特征向量,经 L2 归一化后作为外观描述子
实际应用时可将网络替换为更适合自己场景的重识别模型,但需保持输出特征归一化且维数合理。
外观代价计算
对每个检测框 d_j 提取特征 r_j,每个已确认轨迹 i 维护一个外观特征库 R_i = {r_k^{(i)}},存储该轨迹过去成功关联的 L_k 个特征(默认 L_k=100)。外观匹配度使用最小余弦距离:
d_app(i, j) = min{ 1 - r_j^T r_k^{(i)} | r_k^{(i)} ∈ R_i }
此设计能够容忍目标外观在追踪过程中的缓慢变化,并提升匹配鲁棒性。
级联匹配与综合代价
直接对所有轨迹进行全局匹配可能导致以下问题:被遮挡较久的轨迹因长期未更新,卡尔曼预测不确定性变大,马氏距离不可靠;若仅依赖外观,也可能发生混淆。DeepSORT 采用级联匹配优先为最近活跃的轨迹分配检测,分阶段解决分配问题。
运动门控:马氏距离
首先使用卡尔曼预测的均值与检测框计算马氏距离(平方),衡量预测与检测在位置上的偏离程度:
d_maha(i, j) = (d_j - y_i)^T S_i^{-1} (d_j - y_i)
其中 y_i 是轨迹 i 预测的观测值,S_i 为协方差矩阵。通过卡方分布的 0.95 分位数阈值进行门控,过滤掉运动上不可能的关联。该门控公式为:
b_ij = 1 if d_maha(i, j) ≤ t^{(1)} else 0
综合匹配代价与门控
最终的匹配代价为运动项和外观项的线性加权组合:
c_i,j = λ d_maha(i, j) + (1-λ) d_app(i, j)
只有当同时满足运动门控 b_ij=1 且外观代价低于一定阈值(通常根据训练集统计得出)时,关联才被允许。权重 λ 通常在 0 到 1 之间,控制运动与外观的相对重要性。
级联匹配流程
- 将已确认轨迹按自上次成功匹配以来的帧数升序排列(即最近活跃的优先)。
- 依次处理每个“年龄”分组:对当前年龄组的轨迹,与截至当前未匹配的检测进行门控和代价计算,使用匈牙利算法执行匹配。
- 年龄较大的轨迹之后再匹配,可避免被遮挡久的轨迹“抢走”本应属于活跃轨迹的检测。
- 最后,剩下的未匹配确认轨迹与未匹配检测进入 IoU 匹配阶段,此时不再考虑外观,仅用预测框与检测框的 IoU 进行二次关联,以覆盖外观特征短暂失效(如大幅形变)的情况。
- 仍未匹配的确认轨迹,若超过最大允许丢失帧数则删除;未匹配的检测则初始化为暂定轨迹。
部署与调优建议
外观模型微调
实际场景的物体类别、视角可能与训练集差异较大,建议使用领域数据微调重识别网络。也可以使用更现代的 Transformer 特征提取器替换原始 CNN,但需保证推理速度满足实时要求。
参数选择经验
- 最大丢失帧数:根据场景遮挡频率调整。频繁遮挡可增加到 60-90 帧,需注意计算量和内存。
- 外观特征库大小
L_k:过小则难应对缓慢变化,过大会引入陈旧外观。100 是较通用值。 - 权重
λ:目标外观独特或运动模型误差较大时,降低 λ 增加外观依赖;运动高速或外观混淆严重时,增加 λ。 - 马氏距离门控阈值:对应卡方分布分位数,一般用 0.95 或 0.99,可微调以平衡召回与精确。
实际工程注意点
- 卡尔曼滤波器初始化需合理设置过程噪声和观测噪声协方差矩阵,通常使用对角阵。
- 检测器的输入直接影响跟踪质量,确保检测框稳定、漏检少。
- 当跟踪目标密集时,可降低 IoU 匹配的阈值避免错误合并;对外观特征应使用更严格的门控。
代码实践要点(Python 伪代码思路)
以下为 DeepSORT 主循环的简化逻辑,帮助理解编写实现:
for frame in video:
detections = detector(frame)
# 1. 卡尔曼预测所有跟踪轨迹到当前帧
for track in tracks:
track.predict()
# 2. 提取检测的外观特征
features = extractor(detections)
# 3. 级联匹配(仅针对确认态轨迹)
matches, unmatched_tracks, unmatched_detections = cascade_matching(
confirmed_tracks, detections, features)
# 4. IoU 匹配:处理级联匹配剩余的确认轨迹与检测
iou_matches, unmatched_tracks, unmatched_detections = iou_matching(
unmatched_tracks, unmatched_detections)
# 5. 状态更新
for track_idx, det_idx in matches + iou_matches:
track = confirmed_tracks[track_idx]
det = detections[det_idx]
track.update(det, features[det_idx])
track.appearance_library.append(features[det_idx])
# 6. 未匹配确认轨迹标记为丢失,超过阈值则删除
mark_missed(unmatched_tracks)
# 7. 未匹配检测初始化为暂定轨迹
init_tentative_tracks(unmatched_detections, features)
# 8. 暂定轨迹转正或删除
promote_or_delete_tentative()
总结
DeepSORT 通过在 SORT 的运动模型之上整合深度外观特征与级联匹配策略,大幅降低了长时遮挡下的身份切换频率,保持了在线跟踪的实时性。初学者应重点理解:
- 为何需要外观特征(解决运动不可靠时的关联)
- 外观特征的提取、存储与距离度量方法
- 综合代价与门控的组合使用
- 级联匹配如何防止“老轨迹”抢占匹配
掌握这些核心机理后,可针对具体应用场景调整外观模型与参数,构建鲁棒的多目标跟踪系统。