
TBD系列第三篇来了。前面两篇我们把MOT多目标跟踪的基本概念、评测指标和检测器选择都过了一遍也把数据关联里最基础的匈牙利匹配讲清楚了。这篇文章我们进入真正决定跟踪效果的核心部分运动预测和匹配策略。换句话说检测器只负责告诉你在哪但目标下一帧可能去哪、轨迹之间怎么连全看这一层的设计。如果你已经能跑通一个Track-by-Detection流程却发现ID Switch频繁、轨迹断裂、边缘场景跟着跟着就丢了那这篇大概率能帮你找到症结所在。这一篇的重点不是罗列算法公式而是讲清楚卡尔曼滤波在MOT里到底怎么落地级联匹配为什么比单纯的全局匹配更抗遮挡以及那些常规文档里不会写的参数调优经验。我尽量按自己实际调试的顺序来讲先聊设计取舍再给可复现的配置最后附上排错经验适合看完前两篇、准备自己动手调一套TBD系统的开发者参考。1. 为什么第三篇才碰运动预测——TBD链路的关键次序1.1 TBD流程中的三个关键环节Track-by-Detection从流程上看就三个环节检测、运动预测、数据关联。检测有多重要我们第一篇就聊过检测器直接决定召回率和误检率是整个系统的上限数据关联决定怎么把检测框拼成轨迹是系统能否稳定的骨架。很多入门教程把运动预测当成一个并不起眼的辅助模块觉得无非是拿卡尔曼滤波做几步外推。但实际调过之后你会发现运动预测才是连接检测质量和关联质量的桥梁。检测器输出的是每一帧的检测框如果直接把检测框按IoU去匹配帧率稍微不稳定就会出问题目标被遮挡几帧后位置可能发生不小偏移相邻帧检测结果对应的置信度也起伏不定。这时候如果没有运动预测做“合理的预期”数据关联就只能靠检测框当前帧的几何相似度去猜但现实场景里目标在遮挡期间的位移、目标自身形变都会让几何相似度迅速失效。所以运动预测解决的核心问题是提供“目标的假设位置”让关联算法在匹配时有一个可靠的先验。我在实际调试中发现很多新手一上来就调关联阈值改了又改效果都不明显最后回头一查发现卡尔曼滤波的参数完全是默认值预测框要么跟着检测框剧烈抖动要么在目标短暂丢失后直接“飞”到错误位置。先搞懂运动预测的工作方式再回去调匹配逻辑就顺很多这也是我把这篇放在第三篇的原因。1.2 检测质量对跟踪效果的“放大器效应”关于TBD我们还可以从错误传递的角度看检测器输出的漏检和误检本身不可完全避免但跟踪系统对检测质量的依赖方式并不是线性的。同一个检测器在不同参数配置下ID Switch数量可能差出好几倍这中间的差距往往就是运动预测和关联策略是否合理导致的。举个例子某段监控视频里目标短暂走到柱子后面检测器连续几帧都没有输出。如果卡尔曼滤波的速度外推太激进预测框就会顺着之前的运动方向越走越远等目标从柱子后面出来时预测框已经在几个像素之外了于是数据关联把同一个目标错误地匹配给了别的轨迹或者干脆开辟了一条新轨迹。如果外推太保守预测框基本停在原地目标出遮挡时又需要好几帧来“重新捕获”轨迹同样容易断。检测质量的“锅”最后会放大成跟踪质量的“锅”。所以在TBD里检测、预测、关联这三者的调试顺序特别重要先确定检测器在目标场景下的漏检率和误检率再去匹配策略里选参数。检测器都明显丢目标的情况下运动预测再怎么调也救不回ID Switch的问题。反过来检测器足够好了运动预测和关联策略就是决定系统上限的关键。2. 卡尔曼滤波调参从状态向量到协方差矩阵2.1 状态向量的定义其实是个取舍问题多目标跟踪里用的卡尔曼滤波大多数实现都采用“匀速模型”状态向量一般设计成8维或4维。8维版本是中心点坐标x、y宽高比ratio高度h以及对应的速度vx、vy、vratio、vh。观测值则取当前检测框的x、y、ratio、h。这样的好处是宽高比和高度分开建模能应对目标尺寸变化又不会让模型过于复杂。但用8维还是4维是个取舍问题。8维模型在目标运动比较平稳时预测更准跟踪质量更高但它的参数更多调起来更麻烦对初始协方差和过程噪声也更敏感。4维模型只保留x、y、w、h四个量不显式建模速度等效于假设每帧之间的速度变化很小实现简单、鲁棒性也不错。很多快速原型和资源受限的边缘设备上都倾向4维版本。我的习惯是如果目标运动比较平滑比如车辆、行人直线或缓弯用8维预测准确度带来的收益很明显。如果场景里目标运动轨迹杂乱、频繁加减速比如球类运动、人群聚集8维模型反而容易因为速度估计不准而放大误差这时候4维加一个较小的过程噪声可能更稳。实践中可以两条路都跑一下小规模实验用IDF1和MOTA对比做决定别凭感觉定。2.2 协方差矩阵初始化滤波器对检测的“信任程度”协方差矩阵P是滤波器对当前状态估计不确定性的度量。初始化的时候P不能太小如果太小相当于告诉滤波器“我对初始位置特别信任”结果前几帧里滤波器更相信自己的预测而不是检测结果跟踪容易滞后。P初始值一般取单位矩阵乘一个系数比如P 10 * I让滤波器在刚开始阶段快速接纳检测框的新信息。过程噪声矩阵Q对应运动模型本身的不确定性。Q设得太大相当于对匀速模型非常不信任滤波器几乎只用检测结果预测框会跟着检测框的抖动而抖动Q设得太小滤波器就非常相信“目标继续保持上一帧的运动状态”遇到短暂遮挡或检测偏移时预测框会沿着旧方向跑偏。Q通常可以设为一个对角线小型矩阵比如0.01到0.1之间的数值乘单位阵。我在调试时有个容易忽略的细节测量噪声R也要同时考虑。很多教程默认把R设成1但检测框位置本身的噪声和图像分辨率、检测器性能都有关系。高分辨率监控画面里几像素的检测框偏移可能不算什么同样几像素的偏移放在低分辨率小目标上就是很大的相对误差。如果目标尺寸普遍偏小R可以调低一点让滤波器更愿意相信检测否则预测框会“跟不上”目标。这个“信任程度”的取舍翻译成生活经验就是一个可靠的朋友给的建议你多听一个三心二意的人给的建议你就要多打折扣卡尔曼滤波做的事情本质上也是这个。2.3 坐标体系转换为什么先归一化再做滤波卡尔曼滤波在MOT里最容易踩的隐形坑是坐标体系。有的实现直接在原始像素坐标上做滤波但同一段视频里目标尺寸可能随时变化离镜头近的框大、速度看上去快离镜头远的框小、速度看上去慢。传统监控场景下同样一个行人以相同地面速度走路在画面近端和远端对应的像素位移完全不同。如果不做归一化状态向量里的速度分量会随着目标尺寸和距离变化而不稳定卡尔曼滤波的速度估计也就没有意义。比较好的做法是把检测框坐标归一化到图像尺寸或者至少统一到相对框尺寸的空间里。归一化之后目标速度的含义变成“每帧移动了自身高度的多少比例”更加接近真实三维空间中的运动这样卡尔曼滤波的输出会更平滑数据关联阶段计算马氏距离也更稳定。有人会问直接用像素坐标也能跑啊为什么非要归一化在单一固定场景、目标尺度变化不大的情况下直接用像素坐标确实能跑而且实现更简单。但一旦要换场景、换相机视角或者做多路视频处理就会明显感觉到预测框的抖动和漂移。我建议从一开始就把归一化做进去省得后期排查问题时到处找“为什么目标一变大轨迹就飘”。3. 匹配策略选择级联、贪心与两阶段匹配3.1 运动匹配与外观匹配的互补关系数据关联阶段的匹配距离一般由两部分组成运动距离和外观距离。运动距离常用马氏距离它把卡尔曼滤波预测的均值、协方差和当前检测框的位置结合起来不是单纯算欧氏距离而是会考虑预测的不确定性。外观距离则利用检测框区域的视觉特征比如ReID特征计算余弦相似度或距离。为什么要同时用两种距离因为它们各有所长。运动距离对短时预测很有效帧间隔小、目标移动少时稳定可靠但目标一旦被遮挡几帧预测误差会加大这时马氏距离可能就不够准确了。外观距离则对屏幕内的形变和短时遮挡更鲁棒目标身体角度变一点、走路姿势变一点特征依然有很大概率接近但目标颜色、装束接近时外观特征区分度不足容易让不同目标互相串扰。两个距离融合时通常做加权相加权重怎么设没有万能答案要看你场景中目标的区分特征够不够强。曾经我调一个人群密集场景目标外观特征区分度很差强行提高外观权重反而导致轨迹频繁在相邻目标间横跳后来把运动距离权重调高把外观只作为低置信度检测时的辅助条件ID Switch立刻降了下来。所以调试建议是先用运动距离为主跑通流程确认瓶颈确实是外观区分度不足导致串扰后再逐步增加外观比重。3.2 级联匹配与贪心匹配的实际使用场景级联匹配是当前主流TBD方案里的标配做法。它的基本逻辑是按轨迹的“年龄”分组那些连续多帧都被稳定匹配的老轨迹优先匹配最近才中断过的轨迹次之刚出现的新轨迹最后匹配。这么做是因为老轨迹经过多帧确认置信度更高值得优先保护而新轨迹帧数太少可靠性低优先级自然要靠后。第一次实践级联匹配时你会直观感受到它对目标被短暂遮挡时的友好程度某一个被跟踪了20帧的行人突然被遮挡一瞬级联匹配会努力把他和当前检测框先接上不被后出现的新检测框“抢走轨迹”。这种设计逻辑也好理解已经陪着系统跑了一路的老伙计比刚冒头的新面孔更值得信任。但级联匹配也解决不了所有问题。如果场景中要实时处理的目标数量特别多全局的匈牙利匹配计算量比较大有些工程直接退化成贪心匹配——每步只让优先级的轨迹先去抢最近的检测框抢完就走。贪心匹配速度极快却存在一个缺陷它只保证局部最优密集场景里容易把检测框分配给并不够匹配的轨迹导致后续轨迹交叉错乱。我的经验是目标密度低、对帧率要求高时用贪心匹配目标密度中等以上或场景关系复杂时老老实实做匈牙利匹配通常也就几毫秒到几十毫秒的开销值得。3.3 置信度阈值与动态调整匹配阶段的阈值设置直接影响轨迹的启停行为。如果阈值特别严格检测框必须跟预测框很接近才算是匹配短管漏检和轻微偏移会直接切断轨迹如果阈值特别宽松误检或相近位置的假检测框会被纳入轨迹污染轨迹特征后续更容易发生ID Switch。比较流行的做法是分阶段处理检测置信度。检测器会输出置信度分数高置信度的检测框直接进入匹配流程保证可靠目标优先被关联低置信度的检测框通常代表可能有重影、遮挡或者误检这些可以作为“候选”先做匹配补充或多帧确认后再决定要不要创建新轨迹。我在实际工程里经常用双阶段设计高置信度的检测框走级联匈牙利匹配低置信度的检测框在剩余未匹配集合里再做一轮基于IoU的贪心补充匹配。这样既保证了可靠性又不会错过遮挡边缘的目标。这个双阈值思路有个额外的好处高低置信区间的划分可以动态调整。比如这段视频目标很多检测器平均置信度偏低把高置信阈值设得太高会导致很多真实目标进不了匹配适当下调能提高召回目标稀疏场景里把阈值设高一点可以减少误检轨迹的产生。动态调整依赖你对检测器的了解需要在实际场景里采样分析不能一直沿用默认数字。4. 一个完整调参案例从轨迹频繁切断到平稳跟踪4.1 可复现的最小实验配置为了让你对前面讲的内容有更直观的概念我搭一个小实验来说明调参过程。假设场景是某园区摄像头拍的行人行走视频目标画面跨度中等行人有往同一方向走的也有偶尔停留交谈的。检测器选一个开源的通用目标检测模型不做场景微调直接使用预训练权重。跟踪框架采用最常见的TBD结构卡尔曼滤波预测 级联匹配 ReID外观特征。实验配置大概这样状态向量8维x, y, ratio, h, vx, vy, vratio, vh过程噪声Q初始取对角线元素0.05测量噪声R初始取单位阵1.0级联匹配过程分为三级刚丢失0帧、丢失1到3帧、丢失4到10帧运动门控阈值马氏距离的卡方分位数取13.28对应自由度4约99%置信区间外观融合余弦距离阈值0.4权重0.3轨迹删除条件连续30帧未匹配上任何检测框则删除轨迹这套配置不是最优只是提供基准线。接下来所有改动都基于这个基线方便对照效果。4.2 实测中最容易翻车的三个点第一次跑这套配置我遇到的情况非常典型行人正常行走时轨迹没问题但两个人擦肩而过时ID Switch概率骤然上升行人A从摄像头画面中消失过了一段时间重新出现系统并不认为他是之前那一个人而是又创建了一条新轨迹。我做了三个关键调整花了大概两三个小时最终把ID Switch数量降了一半以上。第一个问题是马氏距离门控太严。两个人的预测框和检测框本来就挨得近加上行人运动有自然摆动的随机性马氏距离经常超过13.28的阈值导致匹配被拒绝。我把门控阈值放宽到17相当于给了目标稍微大一点的匹配容忍空间两次擦肩场景的ID Switch立刻变少。但阈值也不能再继续放宽太宽松会把不同目标也匹配到同一条轨迹上这个度靠可视化逐帧检查来确定。第二个问题是过程噪声Q值过低。行人短时停在原地聊天时卡尔曼滤波的速度状态还保持之前的外推方向预测框不断漂移导致轨迹越来越偏离检测框最终被判定丢失。我把Q从0.05调到0.1让运动模型不那么自信滤波器能更快接受最新检测位置信息停车、折返、起步这些动态场景明显好转。代价是正常行走时预测框抖动变大了一点但总体上优点大于缺点。第三个问题集中在外观特征匹配权重。行人目标的视线方向、服装姿势变化很快ReID特征在不同帧之间的余弦距离本身就波动。权重大了会让两个外观相似的目标抢来抢去权重小了又起不到抗遮挡作用。后来我采取了一个折中方式外观距离只作为“候选近邻”过滤条件不作为硬性否决条件只有当前IoU匹配明显不一致时才使用外观距离决定。这一改系统的整体鲁棒性提升了不少。4.3 小数据调参与迭代节奏有经验的人会在调参时严格控制变量每次只改一个参数并且在固定的短视频片段上做前后对比。我自己习惯的做法是准备一段包含遮挡、交叉、离开视野又返回、短暂停滞等典型情况的2分钟切片先把这段视频的检测结果缓存下来后面调参过程中反复回放同一段比较轨迹质量和ID Switch数量。第一次调参时容易陷入的误区是“全参数一起调”。这样即使效果变好了你也不知道是哪一步产生的作用效果变坏了更不知道如何回退。一次只改一个每次只跑同一个测试切片把结果记录下来这看起来慢实际上是最快的方法。另一方面参数之间不是完全独立的。比如调大Q让目标重新定位更快却可能让预测框输出不稳定从而让IoU匹配变差。所以你在调第二个参数前要先把上一个参数的效果“消化”完确认你是在新的最佳基线上继续改动而不是在原来的基线上做加法。5. 常见问题速查轨迹断裂、ID Switch与僵尸轨迹5.1 轨迹频繁断裂的排查入手点如果你遇到“目标明明还在画面里但轨迹ID却新开了一条”的情况优先检查三处。第一卡尔曼滤波的过程噪声Q是不是设置得太小导致预测跟不上检测的新位置第二马氏距离门控是不是太严尤其是目标贴近其他物体或角度突然变化时第三检测器本身在目标快速移动或转身时容易漏检这决定了你漏接的帧数到底有多长。轨迹断裂并不一定完全是跟踪模块的问题。检测框位置抖动性较大时卡尔曼滤波输出也不稳。碰到这种情况我会先缓存检测框序列统计一下目标每帧检测框中心点到真实中心的偏差由此判断到底是检测不稳定还是跟踪不稳定避免在错误的方向上反复折腾。5.2 ID Switch高发场景的处理经验ID Switch最常出现在两个时刻两个目标相遇又分离、目标被完全遮挡后重新出现。这两个场景本质上有区别相遇分离时外观特征在接近瞬间容易被另一目标的特征短暂抢占导致轨迹归属发生变化被遮挡后重新出现时则是因为轨迹预测位置已偏离实际位置匹配算法没把这份检测框和责任轨迹接上。处理相遇分离可以加入外观特征更新机制每成功匹配一次就按一定比例更新该轨迹的特征参考向量。这样做的好处是目标特征能适应当前帧的状态变化不会一直停留在“旧”照片状态。处理遮挡重出现则要合理设置轨迹存活时间。存活时间太短目标出遮挡后连不上旧轨迹存活时间太长场景里会积累大量僵尸轨迹为后续匹配制造噪声。5.3 僵尸轨迹与虚假轨迹的抑制所谓僵尸轨迹就是目标已经离开视野但系统里还保留着它的“空壳”轨迹。如果这个空壳轨迹在后续帧里恰好预测位置碰上了另一个目标的检测框就可能发生灾难性的错误匹配把新人接在旧身份上。抑制僵尸轨迹的方法是按帧数上限强制删除未被匹配的轨迹同时要注意区分“短时遮挡”和“真正离开”的时间尺度。另外还有一类虚假轨迹通常由低置信度的误检框连续拼接而成。抑制它们需要在创建新轨迹前设置“确认期”候选轨迹只有连续若干帧都匹配到检测框才转为正式轨迹。这个确认期太短会放过误检太长则会让真实目标的新轨迹迟迟建立不起来。具体帧数取决于你场景里检测器的误检率一般取3到6帧比较合理。5.4 快速问题定位参考表现象可能原因优先排查项常见修正方向轨迹频繁断裂Q过小或门控过严目标移动速度、马氏距离分布调大Q放宽马氏距离阈值ID Switch严重外观权重失衡或遮挡恢复失败相遇分离段、遮挡段视频调整特征权重设置轨迹存活期轨迹抖动剧烈Q偏大或R偏大目标匀速段预测框稳定性适当降低Q检查R的标定僵尸轨迹过多轨迹存活时间过长离开视野目标数量缩短未匹配删除帧数新目标迟迟不入轨确认期设置过长或置信度阈过高新目标首次出现帧缩短确认期调节置信度阈值小目标跟丢坐标尺度未归一化低分辨率目标偏移量归一化坐标针对小目标调R最后分享一个我自己的调试习惯调参前先把检测结果缓存下来这样每次调跟踪参数只需要重放缓存检测帧不用反复跑检测器一天能节省大量时间而且缓存之后能非常直观地对照检测框变化判断哪些问题其实出在检测阶段。另外任何参数改动都要在固定测试片段上验证完成后顺手记下改动前后对比哪怕只是记录几个数字时间久了作用都很大。这套方法不一定适合每一个场景但思路是通用的希望对正在搞TBD系统的你有参考价值。