Skip to main content

Command Palette

Search for a command to run...

跟踪算法sort

Published
2 min read

1.引言

在实现对画面当中的目标进行检测后,紧接着就会考虑到场景当中的这几个问题,我检测的目标会往哪个方向走,我检测的目标出现的时间和消失的时间,这就会引入另一个算法:跟踪算法,目前主流的几个跟踪算法方向如下:使用传统跟踪算法(SORT,DeepSORT),传统深度学习的跟踪算法(LSTM),大模型框架下的跟踪算法(MOTR,MOTR2)等。

算法逻辑

SORT的核心主要是有两个:使用卡尔曼滤波用于目标运动的预测和更新,使用匈牙利算法处理数据匹配的问题。

我们使用YOLO可以拿到比较稳定的输出目标框

输入的格式:

BBOX = [x, y, w, h, score, class]

输出格式:携带着稳定ID的跟踪结果

T_BBOX = [track_id, x, y, w, h, score, class]

算法的核心思想:

  • 运动先验:每条轨迹都有KF,先预测当前帧的位置与尺度(得到预测框)。

  • 空间一致:用预测框 vs 检测框的IOU构造代价矩阵。

  • 全局分配:使用匈牙利算法在所有轨迹与检测框做全局最优匹配。

  • 生存管理:新建/确认/保活/删除,抑制噪声与短时漏检。

3.轨迹状态与卡尔曼滤波

3.1状态与量测

状态向量

$$x=[C_x,C_y,s,r,C_x',C_y',s']$$

  • Cx, Cy:框中心;s:面积;r:宽高比w/h

  • 点表示速度项(常速度模型)

量测向量

$$z=[C_x,C_y,s,r]^T$$

3.2 预测与更新

  • Predict:用状态转移矩阵 F 将 𝑥𝑡−1→𝑥𝑡∣𝑡−1,并得到预测协方差 𝑃𝑡∣𝑡−1

  • Update:若和某检测匹配,用量测 𝑧𝑡 做卡尔曼更新,得到 𝑥𝑡∣𝑡、𝑃𝑡∣𝑡;未匹配则仅保留预测(不确定性增加)

4.数据关联

4.1代价矩阵(Cost)

对每个“预测轨迹框” 𝑇𝑖pred与“当前检测框” 𝐷𝑗

$$C = 1-IOU$$

  • 若 IoU𝑖𝑗<iou_threshold(如 0.3),将该对视为不可匹配(代价置大数或直接屏蔽)。

4.2 匈牙利匹配(线性分配)

在代价矩阵 C 上做全局最小化,得到三类集合:

  • matches:配对成功的(轨迹 i ↔ 检测 j)

  • unmatched_tracks:本帧未匹配到检测的轨迹

  • unmatched_dets:本帧未被任何轨迹消费的检测

5.生命周期管理:新建-确认-保活-删除

  • 新建(spawn):对每个未匹配检测,初始化一条新轨迹(KF 状态由检测框转换)。
  • 确认(confirm):为避免噪声检测,轨迹需连续命中 ≥ min_hits(如 3)才标记为 confirmed 并对外输出。出。
  • 保活(ageing):未匹配轨迹仅预测,time_since_update += 1;在 ≤ max_age(如 30 帧)期间允许“隐身”,便于遮挡后“接回”。
  • 删除(prune):time_since_update > max_age 的轨迹被移除。

6.完整工作流程

  • 检测:从检测器取本帧框,按 类别/ROI 过滤。

  • 预测:对所有存活轨迹执行 KF Predict,得到预测框。

  • 造价:计算 预测框 vs 检测框 的 IoU,构造代价矩阵;IoU 低于阈值的对剔除。

  • 匹配:匈牙利算法求全局最优分配,得到匹配/未匹配集合。

  • 更新:匹配上的轨迹执行 KF Update;未匹配轨迹仅预测并记一次未命中。

  • 新建:对未匹配检测生成新轨迹。

  • 清理:删除超龄轨迹;达到 min_hits 的轨迹由 tentative→confirmed

  • 输出:仅输出 confirmed 轨迹作为跟踪结果(用于计数/统计/上游预测)。

7.参考实现

tracks   = []     # 轨迹对象:KF、id、age、hits、time_since_update、status 等
next_id  = 1
iou_thr  = 0.3
min_hits = 3
max_age  = 30

for frame in video_stream:
    dets = detector(frame)                       # [[x1,y1,x2,y2,score,cls], ...]
    dets = filter_by_roi_and_class(dets)

    # 1) KF 预测
    for t in tracks:
        t.kf.predict()
        t.pred_box = state_to_box(t.kf.x)

    # 2) IoU 代价矩阵(IoU < iou_thr 的对置为大数或剔除)
    C = build_cost_matrix(tracks, dets, iou_thr=iou_thr)

    # 3) 匈牙利匹配
    matches, u_trks, u_dets = hungarian_assign(C)

    # 4) 更新匹配到的轨迹
    for i, j in matches:
        z = box_to_meas(dets[j])                 # z = [cx,cy,s,r]
        tracks[i].kf.update(z)
        tracks[i].time_since_update = 0
        tracks[i].hits += 1
        tracks[i].age  += 1
        tracks[i].status = 'confirmed' if tracks[i].hits >= min_hits else 'tentative'

    # 5) 未匹配轨迹仅预测(已在 step 1 完成)
    for i in u_trks:
        tracks[i].time_since_update += 1
        tracks[i].age += 1

    # 6) 为未匹配检测新建轨迹
    for j in u_dets:
        t = new_track_from_det(dets[j], next_id) # 初始化 KF、id、计数器等
        tracks.append(t)
        next_id += 1

    # 7) 删除超龄
    tracks = [t for t in tracks if t.time_since_update <= max_age]

    # 8) 输出仅 confirmed 的轨迹
    outputs = [(t.id, state_to_box(t.kf.x)) for t in tracks if t.status == 'confirmed']
    yield outputs

8.参数选择与工程实践

  • iou_threshold(默认 ~0.3):低了易误配,高了易漏配;小目标/抖动大可稍降(0.2–0.3)。

  • min_hits(2–4):越大越能抑制假框,但轨迹“生效”更慢。

  • max_age(与 FPS 相关):30 FPS 场景可先取 30(≈1s 隐身);低 FPS/遮挡重可取 45–60。

  • 按类分轨:car/bus/truck/person 分别跑一套 SORT,避免跨类错配。

  • 计数/统计:仅对 confirmed 轨迹计数;跨线后对 同 track_id 做短 TTL 去重,防止抖动重复计数。

  • 低 FPS/快速运动:适当调大 KF 的 过程噪声 Q 或 max_age,容忍更大的位移与预测误差。

  • 可视化与日志:保存每帧的匹配关系、未匹配集合、IoU 分布,利于调参与复现。

9.常见问题和增强路线

近距离交汇/遮挡 → ID 互换

  • 原因:SORT 只用 IoU,不看外观。

解决(从轻到重)

  • 运动门控(马氏距离 χ²):将运动不合理的候选对直接剔除。

  • DeepSORT:加入 ReID 外观特征 与 级联匹配(强烈改善 ID 稳定)

  • OC-SORT:用光流/几何一致性改进时间关联(无外观也稳)。

  • BoT-SORT / StrongSORT:更强的外观建模与相机补偿。

  • ByteTrack:高/低置信两阶段关联,拥挤场景召回更高。

  • 移动相机(行车记录仪):考虑 相机运动补偿(CMC) 或选 OC-SORT/BoT-SORT。

  • 多传感器融合:有毫米波/激光雷达时,把 距离/速度 加入门控或代价项,串号率会显著下降。

More from this blog

Opencoda 安装

一、前言:OpenCode 是什么?为什么值得用? 1.1 OpenCode 简介 官网OpenCode | The open source AI coding agent OpenCode 是一个开源的 AI 编程助手,支持: ✅ 在终端(CLI)中直接对话写代码,与ClaudeCodeCLI类似 ✅ 在 VSCode 中辅助写代码 ✅ 自动生成代码、重构代码、解释代码 ✅ 不绑定平台、可自由扩展 ✅ 对开发者非常友好 ✅ 有很多免费的大模型可以使用,不收费不排队 1.2 本教程你能学到什么?...

Feb 3, 20263 min read

树莓派系统安装

1.安装树莓派镜像 首先要访问树莓派的官网找到树莓派的镜像文件,可以在下面这里可以找到:树莓派作系统下载——树莓派 下载好树莓派的镜像后需要使用win32diskimager将镜像刷到sd卡当中,下面是win32diskimager的安装链接: Win32 Disk Imager 下载 | SourceForge.net --- Win32 Disk Imager download | SourceForge.net 安装好后分别使用下面这三个步骤操作:1.选择镜像,2.选择sd卡,3.写入...

Jan 17, 20261 min read

杨涌彪的博客

31 posts