DeepSORT算法流程详解
DeepSORT(Deep Simple Online and Realtime Tracking)是一种多目标跟踪算法,它结合了运动信息(卡尔曼滤波)和外观特征(ReID模型)。以下是结合代码的详细算法流程分析:
代码参考:
- deep_sort/deep_sort/sort/tracker.py
- deep_sort/deep_sort/sort/track.py
- deep_sort/deep_sort/sort/linear_assignment.py
- deep_sort/deep_sort/sort/nn_matching.py
- deep_sort/deep_sort/sort/iou_matching.py
1. 初始化
def __init__(self, metric, max_iou_distance=0.7, max_age=70, n_init=3):
self.metric = metric # 外观特征距离度量器
self.max_iou_distance = 0.7 # IOU匹配阈值
self.max_age = 70 # 最大允许丢失帧数
self.n_init = 3 # 新轨迹确认所需连续匹配帧数
self.kf = kalman_filter.KalmanFilter() # 卡尔曼滤波器
self.tracks = [] # 当前活跃轨迹列表
self._next_id = 1 # 下一个轨迹ID
2. 预测阶段
def predict(self):
for track in self.tracks:
track.predict(self.kf) # 用卡尔曼滤波预测轨迹状态
- 目的:用卡尔曼滤波预测所有轨迹在当前帧的位置(先验估计)。
- 操作:遍历所有轨迹,更新其边界框的预测均值和协方差。
3. 更新阶段
def update(self, detections):
# 1. 匹配检测与轨迹
matches, unmatched_tracks, unmatched_detections = self._match(detections)
# 2. 更新匹配的轨迹
for track_idx, detection_idx in matches:
self.tracks[track_idx].update(self.kf, detections[detection_idx])
# 3. 处理未匹配的轨迹
for track_idx in unmatched_tracks:
self.tracks[track_idx].mark_missed() # 标记丢失
# 4. 处理未匹配的检测
for detection_idx in unmatched_detections:
self._initiate_track(detections[detection_idx]) # 初始化新轨迹
# 5. 删除失效轨迹
self.tracks = [t for t in self.tracks if not t.is_deleted()]
# 6. 更新外观特征数据库
active_targets = [t.track_id for t in self.tracks if t.is_confirmed()]
features, targets = [], []
for track in self.tracks:
if track.is_confirmed():
features += track.features
targets += [track.track_id] * len(track.features)
track.features = [] # 清空缓存
self.metric.partial_fit(np.array(features), np.array(targets), active_targets)
4. 匹配核心 _match()
(1) 分级匹配策略
def _match(self, detections):
# 划分轨迹:已确认 vs 未确认
confirmed_tracks = [i for i,t in enumerate(self.tracks) if t.is_confirmed()]
unconfirmed_tracks = [i for i,t in enumerate(self.tracks) if not t.is_confirmed()]
# 阶段1:级联匹配(已确认轨迹 + 外观特征)
matches_a, unmatched_tracks_a, unmatched_detections = \
linear_assignment.matching_cascade(
gated_metric,
self.metric.matching_threshold,
self.max_age,
self.tracks, detections, confirmed_tracks
)
# 阶段2:IOU匹配(未确认轨迹 + 丢失1帧的轨迹)
iou_track_candidates = unconfirmed_tracks + [
k for k in unmatched_tracks_a if self.tracks[k].time_since_update == 1
]
matches_b, unmatched_tracks_b, unmatched_detections = \
linear_assignment.min_cost_matching(
iou_matching.iou_cost,
self.max_iou_distance,
self.tracks, detections,
iou_track_candidates, unmatched_detections
)
# 合并结果
matches = matches_a + matches_b
unmatched_tracks = list(set(unmatched_tracks_a) | set(unmatched_tracks_b))
return matches, unmatched_tracks, unmatched_detections
(2) 门控外观度量 gated_metric()
def gated_metric(tracks, dets, track_indices, detection_indices):
# 提取检测特征和轨迹ID
features = [dets[i].feature for i in detection_indices]
targets = [tracks[i].track_id for i in track_indices]
# 计算外观代价矩阵
cost_matrix = self.metric.distance(features, targets)
# 应用门控:结合马氏距离过滤不可行匹配
cost_matrix = linear_assignment.gate_cost_matrix(
self.kf, cost_matrix, tracks, dets, track_indices, detection_indices
)
return cost_matrix
5. 关键设计详解
(1) 分级匹配
- 级联匹配(Cascade Matching)
优先处理已确认轨迹(confirmed_tracks
),按丢失时间升序匹配。解决频繁遮挡问题,优先匹配最近出现的轨迹。 - IOU匹配(IOU Matching)
处理未确认轨迹和仅丢失1帧的轨迹。仅依赖运动信息(边界框IOU),避免外观特征不可靠时的错误匹配。
(2) 轨迹生命周期管理
- 新轨迹:需连续匹配
n_init
帧才转为confirmed
。 - 丢失轨迹:连续丢失
max_age
帧后删除。 - 未确认轨迹:在
n_init
帧内丢失即删除。
(3) 外观特征更新
- 收集所有已确认轨迹的特征。
- 更新距离度量器的特征库,使外观模型适应目标变化。
- 清空轨迹的特征缓存(
track.features = []
)。
(4) 门控机制
- 马氏门控:计算检测与预测位置间的马氏距离,过滤掉统计上不可能的匹配。
- 外观门控:结合余弦距离阈值排除外观差异过大的匹配。
6. 完整工作流程
- 预测:卡尔曼滤波预测所有轨迹位置。
- 匹配:
- 级联匹配:外观特征 + 马氏门控(已确认轨迹)。
- IOU匹配:运动信息(未确认/短期丢失轨迹)。
- 更新:
- 匹配成功:卡尔曼滤波更新轨迹状态。
- 未匹配轨迹:标记丢失,超时则删除。
- 未匹配检测:初始化为新轨迹。
- 清理:删除失效轨迹。
- 特征更新:收集特征并更新外观模型。
7. 优势分析
- 运动+外观融合:卡尔曼滤波处理短时遮挡,ReID特征处理长时遮挡。
- 分级匹配:优先保证高置信度轨迹的匹配质量。
- 增量学习:动态更新外观特征库,适应目标外观变化。
- 实时性:级联匹配和IOU匹配的复杂度可控,满足实时需求。
通过这种设计,DeepSORT在复杂场景(如遮挡、外观相似目标)中显著提升了跟踪鲁棒性。