Yolov5-DeepSort之级联匹配

 

级联匹配

级联匹配算法是对于确定态的跟踪目标利用匹配的优先程度进行多级优先匹配,该匹配策略是以余弦距离结合马氏距离为代价矩阵的匈牙利匹配算法


1. 代码详解

这里只展示相关代码,整个deepsort工程见本人github,代码里添加详细注释,帮助大家理解。

def matching_cascade(distance_metric, max_distance, cascade_depth, tracks, detections,
                     track_indices=None, detection_indices=None):
    # 分配track_indices和detection_indices两个列表
    if track_indices is None:
        track_indices = list(range(len(tracks)))
    if detection_indices is None:
        detection_indices = list(range(len(detections)))

    # 初始化匹配集matches M ← ∅ 
    # 未匹配检测集unmatched_detections U ← D 
    unmatched_detections = detection_indices
    matches = []
    # 由小到大依次对每个level的tracks做匹配
    for level in range(cascade_depth):
        # 如果没有detections,退出循环
        if len(unmatched_detections) == 0:  # No detections left
            break
        # TODO 跳过 track_indices == []
        # 当前level的所有tracks索引
        # 步骤6:Select tracks by age
        track_indices_l = [
            k for k in track_indices
            if tracks[k].time_since_update == 1 + level
        ]
        # 如果当前level没有track,继续
        if len(track_indices_l) == 0:  # Nothing to match at this level
            continue
            
        # 步骤7:调用min_cost_matching函数进行匹配 
        matches_l, _, unmatched_detections = \
            min_cost_matching(
                distance_metric, max_distance, tracks, detections,
                track_indices_l, unmatched_detections)
        matches += matches_l # 步骤8
    unmatched_tracks = list(set(track_indices) - set(k for k, _ in matches))  # 步骤9
    return matches, unmatched_tracks, unmatched_detections

def min_cost_matching(distance_metric, max_distance, tracks, detections,
                      track_indices=None, detection_indices=None):
    if track_indices is None:
        track_indices = np.arange(len(tracks))
    if detection_indices is None:
        detection_indices = np.arange(len(detections))

    if len(detection_indices) == 0 or len(track_indices) == 0:
        return [], track_indices, detection_indices  # Nothing to match.

    # 计算成本矩阵
    cost_matrix = distance_metric(
        tracks, detections, track_indices, detection_indices)
    cost_matrix[cost_matrix > max_distance] = max_distance + 1e-5

    # 执行匈牙利算法,得到指派成功的索引对,行索引为tracks的索引,列索引为detections的索引
    row_indices, col_indices = linear_assignment(cost_matrix)

    matches, unmatched_tracks, unmatched_detections = [], [], []
    # 找出未匹配的detections
    for col, detection_idx in enumerate(detection_indices):
        if col not in col_indices:
            unmatched_detections.append(detection_idx)
    # 找出未匹配的tracks
    for row, track_idx in enumerate(track_indices):
        if row not in row_indices:
            unmatched_tracks.append(track_idx)
    # 遍历匹配的(track, detection)索引对
    for row, col in zip(row_indices, col_indices):
        track_idx = track_indices[row]
        detection_idx = detection_indices[col]
        # 如果相应的cost大于阈值max_distance,也视为未匹配成功
        if cost_matrix[row, col] > max_distance:
            unmatched_tracks.append(track_idx)
            unmatched_detections.append(detection_idx)
        else:
            matches.append((track_idx, detection_idx))
    return matches, unmatched_tracks, unmatched_detections

# 级联匹配的代价矩阵
def gated_metric(tracks, dets, track_indices, detection_indices):
    features = np.array([dets[i].feature for i in detection_indices])  # 检测特征
    targets = np.array([tracks[i].track_id for i in track_indices])    # 跟踪 id

    # 使用余弦距离计算代价矩阵 (外观特征)
    cost_matrix = metric.distance(features, targets)
    # 如果要一个轨迹去匹配两个外观特征相似的 detection,也很容易出错;
    # 使用马氏距离 (运动特征) 过滤外观特征相似但距离较远的 detection,从而减少错误的匹配。
    cost_matrix = linear_assignment.gate_cost_matrix(kf, cost_matrix, tracks, dets,
                                                     track_indices, detection_indices)

    return cost_matrix

# Split track set into confirmed and unconfirmed tracks.
# 将轨迹分为确定态和不确定态
confirmed_tracks = [i for i, t in enumerate(tracks) if t.is_confirmed()]
unconfirmed_tracks = [i for i, t in enumerate(tracks) if not t.is_confirmed()]

# Associate confirmed tracks using appearance features.
# 对确定态的轨迹进行级联匹配 (外观和运动特征匹配),得到匹配的tracks、不匹配的tracks、不匹配的detections
matches_a, unmatched_tracks_a, unmatched_detections = linear_assignment.matching_cascade(
    gated_metric, metric.matching_threshold, max_age,
    tracks, detections, confirmed_tracks)

本文作者: 崔玉君
版权声明: 转载请注明出处!

Enjoy! :ghost: :ghost: :ghost:


If you like TeXt, don’t forget to give me a star. :star2:

Star This Project