想象你走进深夜的机场塔台。雷达屏幕上几十个光点缓缓移动,管制员不会只喊一句“那边有飞机”,而是给每个光点分配一个航班号:CZ3456 正在爬升,MU5122 正在减速,3U8882 即将进入我的区域。这个从“看见一个光点”到“知道它是谁、要去哪、会不会和谁相遇”的过程,就是动态障碍物跟踪的缩影。 自动驾驶汽车也有一座自己的“塔台”。激光雷达、摄像头、毫米波雷达每几十毫秒送来一批检测框或点云,但这些只是“这一帧看到了一个对象”,并不知道上一帧的同一个对象在哪里。动态障碍物跟踪要做的,就是把零散的观测串成连续、带身份信息的轨迹,并预测它下一步的位置。本文就以“塔台管制员”为主角,带你从概念、算法、评估到工程调优,完整理解这项自动驾驶感知系统的关键能力。

岗位关联

对 AI 从业者而言,动态障碍物跟踪是打通“感知-预测-规划”链条的必经之路。理解它,你才能从“会用检测模型”进阶到“能设计完整自动驾驶感知系统”。

目录
  1. 可视化演示
  2. 跟踪基础概念
  3. 感知输入解析
  4. 数据关联配对
  5. 运动状态估计
  6. 轨迹生命周期
  7. 多目标评估指标
  8. 实战调优策略
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

演示多目标检测关联、卡尔曼滤波状态估计与轨迹预测三大环节,直观展示自动驾驶如何在连续帧中锁定并预测障碍物运动。

本节配有交互动效(进入视口后自动加载,约 3KB)。

检测关联 检测框与轨迹匹配 匈牙利算法 分配ID实现跨帧持续跟踪

跟踪基础概念

深夜的机场塔台,雷达屏幕上几十个光点缓缓移动。管制员不会只喊一声“那边有飞机”,而是给每个光点分配一个航班号:CZ3456 正在爬升,MU5122 正在减速……这个从“看见”到“知道是谁、要去哪”的过程,就是动态障碍物跟踪的缩影。

自动驾驶汽车也有自己的“雷达屏幕”。激光雷达、摄像头、毫米波雷达每几十毫秒送来一批检测框或点云,但它们只是“这帧看见了一个对象”,并不知道上一帧的同一个对象在哪里。动态障碍物跟踪要做的,就是把这些零散观测串成连续、带身份信息的轨迹。

在感知系统里,跟踪位于检测之后、轨迹预测与规划之前。它维护一个 Track 列表,每个 Track 拥有唯一 ID、位置速度、历史轨迹和置信度。动态障碍物指会主动或被动移动的交通参与者,包括车辆、行人、骑行者;静态障碍物通常交给地图与语义分割处理。跟踪器的输出状态可以表示为一个向量:

就像管制员靠航班号组织所有调度动作,跟踪器靠 ID 让后续预测、关联、规划都有抓手。没有 ID,传感器数据只是一地散落的珠子;有了跟踪,珠子才被串成项链。

xk=[xk, yk, vx,k, vy,k]T\mathbf{x}_k = [x_k,\ y_k,\ v_{x,k},\ v_{y,k}]^T
  1. 状态向量\( \mathbf{x}_k \) 表示第 \( k \) 帧目标的完整运动状态,是一个四维列向量。
    xk\mathbf{x}_k
  2. 位置坐标\( x_k,\ y_k \) 是目标在自车坐标系或图像坐标系下的位置。
    xk, ykx_k,\ y_k
  3. 运动速度\( v_{x,k},\ v_{y,k} \) 是 \( x \)、\( y \) 方向的速度,用于预测下一帧位置。
    vx,k, vy,kv_{x,k},\ v_{y,k}
  4. 转置符号\( T \) 表示把行向量转成列向量,方便矩阵运算。
    (⋅)T(\cdot)^T

感知输入解析

塔台管制员从不只依赖一台雷达,还有 ADS-B 广播、天气雷达、肉眼观察。每种信息源都有自己的脾气:雷达看得远但不够细,ADS-B 有身份却可能失效。自动驾驶的感知系统同样如此。

摄像头像管制员的眼睛,纹理与颜色丰富,能分辨交通灯、车道线和行人;但在黑夜、逆光、雨雾中会看不清,单目也没有可靠深度。激光雷达像高精度三维扫描仪,通过发射激光获得点云,能准确测距,但雨雪天气会衰减、成本较高。毫米波雷达更像传统雷达,测距测速可靠,全天候工作,但角度分辨率低,难以区分路边的栏杆和行人。

这些感知源经过目标检测后,输出“检测框”或“目标点”,在跟踪系统中称为观测(Measurement)。不同传感器输出维度不同:图像是 2D 框,激光雷达是 3D 框或聚类中心,毫米波雷达是目标点加径向速度。跟踪器必须理解每个观测的坐标系和噪声水平,才能做好后续的关联与滤波。

没有完美的传感器,只有互补的组合。就像塔台把雷达高度、ADS-B 计划、飞行员语音交叉印证,自动驾驶也需要在时间同步和坐标统一后,把多源观测揉进同一个跟踪框架。

数据关联配对

雷达屏幕上每帧都会冒出新的光点,管制员首先要回答:这个新光点,是刚才那架飞机的新位置,还是一架刚进入区域的新飞机?这个“认领”的过程,就是数据关联。

数据关联发生在已有轨迹与新检测之间。每条轨迹会给出一个预测位置,每个检测也有自己的位置;关联算法计算它们之间的相似度,比如中心距离或 IoU(交并比)。最简单的做法是最近邻匹配:每个检测找离它最近的轨迹;更稳健的做法是全局匹配。

当多个目标挤在一起时,最近邻可能互相打架。工程上常用贪心策略:先按代价从小到大排序,优先绑定最确信的一对;想要全局最优则用匈牙利算法,把关联问题建模成二分图最小代价匹配:

关联就像塔台逐一点名:点对了,轨迹延续;点错了,两架飞机的身份就会张冠李戴,后续所有预判都失去意义。数据关联是跟踪防混淆的第一道防线。

\min \sum_{i=1}^{m}\sum_{j=1}^{n} c_{ij} x_{ij}\quad \text{s.t.}\quad\sum_{i=1}^{m} x_{ij} \le 1,\quad\sum_{j=1}^{n} x_{ij} \le 1,\quadx_{ij} \in \{0,1\}
  1. 代价矩阵\( c_{ij} \) 表示第 \( i \) 条轨迹与第 \( j \) 个检测之间的不相似度,通常用 \( 1 - \text{IoU} \) 或距离表示。
    cijc_{ij}
  2. 决策变量\( x_{ij} = 1 \) 表示把轨迹 \( i \) 与检测 \( j \) 配对。
    xij∈{0,1}x_{ij} \in \{0,1\}
  3. 行约束每个检测最多被一条轨迹认领,防止一对多。
    ∑i=1mxij≤1\sum_{i=1}^{m} x_{ij} \le 1
  4. 列约束每条轨迹最多匹配一个检测,防止分身。
    ∑j=1nxij≤1\sum_{j=1}^{n} x_{ij} \le 1
  5. 目标函数使所有配对的总代价最小,也就是让身份错配的总风险最低。
    min⁡∑i=1m∑j=1ncijxij\min \sum_{i=1}^{m}\sum_{j=1}^{n} c_{ij} x_{ij}

运动状态估计

管制员看到飞机当前位置后,会按照速度和航向估算几秒后的位置。卡尔曼滤波做的就是这件事:先按运动模型往前推一步,再用新的观测修正,反复循环。

在自动驾驶中,目标通常用匀速运动模型近似,认为短时间内速度基本不变。状态方程和测量方程写成:

卡尔曼滤波的核心是“预测”与“校正”交替。校正公式可以写成:

卡尔曼滤波之所以被广泛使用,是因为它把“模型预测的不确定度”和“传感器测量的不确定度”放在同一把尺子上比较。预测噪声大、观测准,就多信观测;反之多信预测。就像塔台不会因为一次雷达回波抖动就大幅改变航线判断,卡尔曼滤波也在“惯性预测”和“新鲜观测”之间取折中,让轨迹平滑而灵敏。

xk=Fxk−1+wk,zk=Hxk+vk\mathbf{x}_k = \mathbf{F}\mathbf{x}_{k-1} + \mathbf{w}_k,\qquad\mathbf{z}_k = \mathbf{H}\mathbf{x}_k + \mathbf{v}_k
  1. 预测状态\( \hat{\mathbf{x}}_k^- \) 是根据上一帧推出来的先验位置。
    x^k−\hat{\mathbf{x}}_k^-
  2. 观测残差\( \mathbf{z}_k - \mathbf{H}\hat{\mathbf{x}}_k^- \) 是“实际观测”与“预测观测”的差距。
    zk−Hx^k−\mathbf{z}_k - \mathbf{H}\hat{\mathbf{x}}_k^-
  3. 卡尔曼增益\( \mathbf{K}_k \) 是一个权衡系数,决定相信观测多一点还是相信预测多一点。
    Kk\mathbf{K}_k
  4. 修正状态\( \hat{\mathbf{x}}_k \) 是融合后的后验状态,也就是最终输出的平滑跟踪结果。
    x^k\hat{\mathbf{x}}_k

轨迹生命周期

一架身份不明的飞机突然出现在雷达边缘,管制员不会马上给它正式航班号,而是先标“未知机”,连续几帧确认后才建立档案。轨迹生命周期遵循同样的谨慎逻辑。

跟踪器收到首个检测时,不会立刻输出给下游,而是创建 Tentative(暂定)轨迹。只有当它连续若干帧都被关联成功,才升级为 Confirmed(确认)。被确认后,每一帧成功关联都会“续命”;一旦没有匹配观测,轨迹进入 Lost(丢失)状态。

真正困难的是遮挡。目标被大车或路边建筑挡住三五帧时,跟踪器仍会用运动模型继续预测,这叫 Coasting(滑行预测),同时把失配计数加一。如果目标重新出现且落在预测门内,就恢复关联,ID 保持不变。超过阈值仍找不到,才删除轨迹。

生命周期的核心是“保守确认、宽容保持、果断删除”。就像塔台档案管理:没有足够证据不建档,证据确凿不轻易销档,确认彻底离开才归档。

status={Tentative,hits<NconfirmConfirmed,hits≥NconfirmLost,misses≥Ndelete\text{status} =\begin{cases}\text{Tentative}, & \text{hits} < N_{\text{confirm}}\\\text{Confirmed}, & \text{hits} \ge N_{\text{confirm}}\\\text{Lost}, & \text{misses} \ge N_{\text{delete}}\end{cases}
  1. 暂定轨迹命中次数不足 \( N_{\text{confirm}} \) 时,只保留不完全可信的候选身份。
    hits<Nconfirm\text{hits} < N_{\text{confirm}}
  2. 确认轨迹连续命中达到阈值后,正式交付给下游规划模块。
    hits≥Nconfirm\text{hits} \ge N_{\text{confirm}}
  3. 丢失轨迹连续丢失观测次数超过 \( N_{\text{delete}} \),轨迹被删除并释放 ID。
    misses≥Ndelete\text{misses} \ge N_{\text{delete}}

多目标评估指标

如何评价一位管制员干得好不好?不能只看雷达上有没有飞机,还要看他有没有跟丢、有没有把 A 机当成 B 机。自动驾驶跟踪也需要一套“考核表”。

多目标跟踪最常用的指标是 MOTA(多目标跟踪准确度),它把三类错误统一折算:误检 FP、漏检 FN 和身份切换 IDS。公式如下:

MOTA 高不代表完美:它可能仍伴随大量 ID Switch,而规划层最怕身份乱跳——一辆车忽然变成另一辆车,紧急制动就会误判。所以工程上还会单独看 IDS 和 MOTP(目标位置精度),并关注算法能否在 20~30 Hz 甚至更高帧率下实时运行。

评价指标就是塔台考核的“红黑榜”:既看总准度,也看身份错乱次数。只有多指标一起看,才不会被一个漂亮分数骗过去。

MOTA=1−∣FP∣+∣FN∣+∣IDS∣∣GT∣\text{MOTA} = 1 - \frac{|\text{FP}| + |\text{FN}| + |\text{IDS}|}{|\text{GT}|}
  1. 误检 FP本来没有目标,检测器却输出一个框。
    FP\text{FP}
  2. 漏检 FN目标存在但没被检出。
    FN\text{FN}
  3. 身份切换 IDS同一个目标的 ID 发生跳变,例如被重新编号。
    IDS\text{IDS}
  4. 真值数量 GT人工标注的标准目标总数。
    GT\text{GT}
  5. 归一化与补数把三类错误总数除以 GT,再用 1 减去,得到 0~1 之间的准确率。
    1−∣FP∣+∣FN∣+∣IDS∣∣GT∣1 - \frac{|\text{FP}| + |\text{FN}| + |\text{IDS}|}{|\text{GT}|}

实战调优策略

再好的管制流程也要靠反复演练和参数微调。自动驾驶跟踪器同样要在开放道路前,经历大量仿真、封闭场地和路测迭代。

先调关联阈值。IoU 阈值设得高,两个框稍微分开就被当成新目标,轨迹碎成一段段;设得低,两个不同目标会被并成一个,ID 混淆。工程上通常用验证集的 MOTA 和 IDS 做参数扫描,找到平衡点。

更难啃的是遮挡、切入、密集人群。这时只靠单传感器不够,需要把相机、毫米波雷达、激光雷达融合:先做时间戳对齐和坐标标定,再把多源观测送入同一跟踪器。白天依赖相机细节,黑夜或雨雾依赖雷达和激光雷达。融合不是简单相加,而是各取所长。

工程迭代方法像塔台复盘:把路测中的 bad case 录下来回放,看关联矩阵、滤波增益、轨迹状态,找到错跟或丢跟的根因,再更新参数或模型,重新回到 MOTA/IDS 榜单验证。这样循环下去,跟踪系统才会越来越接近一个冷静老练的“虚拟管制员”。

AI 应用场景

城市路口行人跟踪

阶段:感知融合与动态跟踪

解决的问题:传统单帧检测只能给出当前帧的检测框,无法判断画面里连续出现的行人是同一个人还是不同的人。路口行人互相遮挡、姿态变化大,单帧检测容易出现漏检和跳变。动态障碍物跟踪通过数据关联和卡尔曼滤波,维持每个行人的 ID,并平滑位置轨迹,让下游 AEB 或规划模块能判断“这个人是否在朝车辆移动”。

具体案例:一辆自动驾驶汽车在左转路口遇到三组过街行人。其中一个行人被前方广告牌遮挡了 4 帧,跟踪器进入 Coasting 状态,用匀速模型持续外推;行人重新出现后,跟踪器在预测门内找回他,ID 保持不变,车辆平稳减速让行,没有急刹。

高速 NOA 邻车切入预警

阶段:动态目标管理与预测

解决的问题:高速场景下,旁车道车辆频繁切入,检测器偶尔会漏掉被 A 柱遮挡的车辆。传统方法只输出“当前有没有车”,难以判断“这辆车是不是刚才那辆在逼近的车”。跟踪系统为每个邻车维护轨迹和速度,提前判断切入意图。

具体案例:某车型的高速领航辅助在行驶中,一辆白色 SUV 从右侧车道快速切入。跟踪器连续 8 帧关联成功,确认轨迹后把该车的横向速度传给预测模块,系统提前 1.2 秒减速,避免不必要的紧急制动。

Python 演示

python74 行
import random  def iou(box1, box2):    x1 = max(box1[0], box2[0])    y1 = max(box1[1], box2[1])    x2 = min(box1[0] + box1[2], box2[0] + box2[2])    y2 = min(box1[1] + box1[3], box2[1] + box2[3])    inter = max(0.0, x2 - x1) * max(0.0, y2 - y1)    area1 = box1[2] * box1[3]    area2 = box2[2] * box2[3]    return inter / (area1 + area2 - inter + 1e-9)  class Track:    def __init__(self, box):        self.box = list(box)        self.vx = 0.0        self.vy = 0.0        self.hit_count = 0        self.lost_count = 0     def update(self, det):        self.vx = det[0] - self.box[0]        self.vy = det[1] - self.box[1]        self.box = list(det)        self.hit_count += 1        self.lost_count = 0  class TrackManager:    def __init__(self):        self.tracks = []     def update(self, detections, iou_thresh=0.3):        assigned = [False] * len(detections)        for track in self.tracks:            best_iou = iou_thresh            best_idx = -1            for i, det in enumerate(detections):                if assigned[i]:                    continue                score = iou(track.box, det)                if score > best_iou:                    best_iou = score                    best_idx = i            if best_idx >= 0:                assigned[best_idx] = True                track.update(detections[best_idx])            else:                track.lost_count += 1         for i, det in enumerate(detections):            if not assigned[i]:                self.tracks.append(Track(det))         self.tracks = [t for t in self.tracks if t.lost_count <= 5]  if __name__ == "__main__":    random.seed(42)    manager = TrackManager()    truth = [[10, 10], [60, 40], [110, 70]]    for step in range(8):        dets = []        for i, pos in enumerate(truth):            truth[i] = [pos[0] + 2, pos[1] + 1]            dets.append([                truth[i][0] + random.uniform(-1.0, 1.0),                truth[i][1] + random.uniform(-1.0, 1.0),                8, 8            ])        manager.update(dets)        print("step", step, "track_count", len(manager.tracks))
目的:演示一个极简的多目标跟踪器,用 IoU 做贪心数据关联,用简单速度和位置更新维护轨迹生命周期。
  1. return inter / (area1 + area2 - inter + 1e-9)计算两个检测框的交并比 IoU,值越接近 1,说明两个框越像同一个目标。
  2. if score > best_iou:在未分配的检测中找 IoU 最大的候选,体现贪心关联策略。
  3. track.update(detections[best_idx])找到匹配后,用新检测更新轨迹状态,相当于“管制员确认这架飞机的新位置”。
  4. self.tracks.append(Track(det))没有匹配到任何旧轨迹的检测,会被创建为新轨迹,也就是“新光点建档”。
  5. self.tracks = [t for t in self.tracks if t.lost_count <= 5]连续丢失超过 5 帧的轨迹被删除,对应轨迹生命周期中的删除策略。

常见误区

误区我认为跟踪和检测是一样的,模型每次输出检测框,把这些框连起来就是跟踪。

正解检测只回答“这一帧哪里有障碍物”,不回答“它是不是上一帧那个物体”。跟踪器需要在检测结果之上做数据关联、状态估计和轨迹管理,才能维持 ID 的连续。就像管制员不能只看雷达上有没有光点,还要知道每个光点是哪架飞机。

为何常见:很多目标检测视频会直接在画面上叠加 ID 和轨迹,看起来像是检测模型自己完成的,容易让人忽略背后的跟踪模块。

误区既然有卡尔曼滤波预测,目标被挡住也没关系,模型能一直算出准确位置。

正解卡尔曼滤波是有不确定度的预测。没有新观测输入时,预测协方差会不断增大,位置会越来越不可信。工程上必须配合轨迹生命周期,设置丢失上限,不能无限“脑补”。

为何常见:科普文章常把卡尔曼滤波描述成“预测神器”,忽略了它同样依赖观测来校正确实存在的不确定性。

误区模型评估报告里 MOTA 到了 95%,我就认为跟踪系统已经完美无缺。

正解MOTA 把 FP、FN、IDS 折算成一个综合分,但它不反映轨迹是否平滑,也不反映预测框的位置精度。规划模块真正关心的 ID 稳定性,还要单独看 ID Switch;位置精度要看 MOTP。

为何常见:MOTA 是论文里最常见的单指标,读者容易把它当成“唯一答案”,忽略它背后的多个分项。

误区只要把摄像头、激光雷达、毫米波雷达全装上,跟踪效果肯定会自动变好。

正解多传感器融合必须先做时间戳对齐和坐标系标定。如果标定有误差,同一个目标在两种传感器里会变成两个不同的观测,反而增加关联混淆。融合是系统工程,不是简单堆硬件。

为何常见:“多即好”是常见直觉,但感知系统更看重的是一致、可靠、可校准的输入。

面试题

Q1. 动态障碍物跟踪中“跟踪”最核心的目标是?

单选题 · easy

  • A.逐帧检测目标
  • B.跨帧维持身份← 正确答案
  • C.识别静态道路
  • D.提高相机帧率

答案:B。跟踪的本质不是“每帧找出目标”,而是把不同帧的同一个目标关联起来,维持稳定的 ID。检测只是跟踪的输入。

Q2. 毫米波雷达相对相机的主要优势是?

单选题 · easy

  • A.色彩与纹理信息
  • B.全天候测距测速← 正确答案
  • C.点云稠密且便宜
  • D.能识别车道线

答案:B。毫米波雷达在雨雾黑夜等恶劣天气下仍能测距测速,这是它最大的价值。相机虽然纹理丰富,但受光照影响大。

Q3. 数据关联要解决的问题是?

单选题 · easy

  • A.新观测匹配旧轨迹← 正确答案
  • B.检测框颜色增强
  • C.提高传感器帧率
  • D.训练检测模型参数

答案:A。数据关联的核心是判断“这个新观测属于哪条旧轨迹”,就像塔台辨识雷达光点是哪架飞机。

Q4. 新目标首帧出现时,跟踪器通常先创建什么轨迹?

单选题 · mid

  • A.暂定轨迹← 正确答案
  • B.确认轨迹
  • C.删除轨迹
  • D.融合轨迹

答案:A。为避免单帧误检污染系统,新目标先建 Tentative 暂定轨迹,连续几帧确认后才升级为 Confirmed。

Q5. 下列哪些属于轨迹生命周期状态?

多选题 · mid

  • A.暂定与确认← 正确答案
  • B.更新与保持← 正确答案
  • C.遮挡与丢失← 正确答案
  • D.融合与规划

答案:ABC。轨迹有暂定、确认、保持、丢失、删除等状态;融合与规划属于下游模块,不是轨迹自身的生命周期状态。

Q6. MOTA 中的三类误差是?

单选题 · mid

  • A.误检漏检与ID切换← 正确答案
  • B.相机标定与时间同步
  • C.目标大小与运动速度
  • D.图像亮度与颜色对比

答案:A。MOTA 综合了 FP(误检)、FN(漏检)和 IDS(身份切换),用真值总数归一化后得到跟踪准确度。

Q7. 多传感器融合前必须处理哪些问题?

多选题 · hard

  • A.时间戳对齐← 正确答案
  • B.坐标系标定← 正确答案
  • C.检测框颜色
  • D.车道线颜色

答案:AB。摄像头、激光雷达、毫米波雷达采样时刻和坐标系不同,如果时间戳和标定不一致,同一个目标会变成两个观测,导致关联混乱。

Q8. 匈牙利算法在数据关联中的主要作用是?

单选题 · hard

  • A.全局最优配对← 正确答案
  • B.局部最近配对
  • C.随机均匀配对
  • D.按时间排序配对

答案:A。匈牙利算法通过优化总代价矩阵,得到全局最优的一对一匹配,比逐个最近邻更稳健,适合密集场景。

Q9. 目标被长时间遮挡后重新出现,最容易出现哪类问题?

单选题 · extreme

  • A.身份切换错误← 正确答案
  • B.相机内参漂移
  • C.激光雷达积灰
  • D.道路结构变化

答案:A。长时间遮挡后,预测位置可能偏离真实位置,重出现时可能被关联到新轨迹,导致 ID Switch。这正是 IDS 指标要重点监控的问题。

Q10. 关于多目标跟踪评估,正确的说法是?

多选题 · mid

  • A.MOTA高不等于无ID切换← 正确答案
  • B.IDSwitch记录跳变次数← 正确答案
  • C.只看检测精度即可
  • D.关联错误导致跳变← 正确答案

答案:ABD。MOTA 是综合指标,高不代表没有身份切换;ID Switch 专门统计身份跳变;数据关联是导致 ID 跳变的主要来源。跟踪评估不能只看检测精度。