3、SORT算法核心思想:基于检测的跟踪范式、状态估计与数据关联、算法流程总览

好,咱们今天来聊聊SORT算法的核心思想。说实话,SORT这个名字起得挺直白的——Simple Online and Realtime Tracking。简单、在线、实时,这三个词就是它的全部追求。我在2017年第一次看到这篇论文时,心里想的是:「这也太简单了吧?」但后来在实际项目中跑起来,才发现简单的东西往往最管用。

3.1 基于检测的跟踪范式(Tracking-by-Detection)

SORT属于典型的「基于检测的跟踪」范式。什么意思呢?说白了就是:我不负责找目标,我只负责把检测框连成轨迹

整个流程分两步走:

  • 第一步:检测器干活——用Faster R-CNN、YOLO这类模型,在每一帧里找出所有目标,输出一堆边界框(bounding box)。
  • 第二步:跟踪器接手——把当前帧的检测框,和上一帧已有的轨迹做匹配。匹配上了就更新轨迹,没匹配上就新建轨迹或删除轨迹。

你可能会问:「为什么不直接用检测器逐帧检测,非要搞个跟踪器?」嗯,这个问题我刚开始也有。后来发现,检测器偶尔会漏检、会抖动,而跟踪器能利用运动信息把这些坑填上。举个例子,我在做行人跟踪时,检测器经常在遮挡瞬间丢掉目标,但跟踪器通过卡尔曼滤波预测的位置,能帮我把目标「拽」回来。

核心要点:检测器提供观测,跟踪器提供预测。两者互补,缺一不可。

3.2 状态估计:卡尔曼滤波的妙用

SORT里的状态估计,用的是卡尔曼滤波。别被这个名字吓到,其实它的思想很朴素:用上一帧的状态,预测当前帧的位置;再用当前帧的观测,修正这个预测

在SORT中,每个目标的状态用一个8维向量表示:

[u, v, s, r, u_dot, v_dot, s_dot, r_dot]

其中:

  • u, v —— 边界框中心点的像素坐标
  • s —— 边界框的面积(宽×高)
  • r —— 宽高比(假设不变)
  • u_dot, v_dot, s_dot, r_dot —— 对应的速度

我个人习惯把卡尔曼滤波拆成两个阶段来理解:

阶段 做什么 输入 输出
预测(Predict) 用匀速运动模型,估计目标下一帧的位置 上一帧的状态 当前帧的预测状态
更新(Update) 用检测器的观测值,修正预测结果 预测状态 + 检测框 修正后的状态

避坑指南:我曾经在项目中把速度初始值设得太大,导致卡尔曼滤波在头几帧疯狂震荡。后来学乖了,速度初始值一律设为0,让滤波器自己慢慢收敛。你想想看,目标刚出现时你根本不知道它跑多快,何必强行猜一个呢?

3.3 数据关联:IOU匹配与匈牙利算法

数据关联,说白了就是「谁跟谁是一对」的问题。SORT的做法非常粗暴:用IOU(交并比)来衡量检测框和预测框的相似度,然后用匈牙利算法做最优匹配

具体流程是这样的:

  1. 对每个已有的轨迹,用卡尔曼滤波预测出它在当前帧的边界框。
  2. 计算每个预测框和每个检测框的IOU值,形成一个代价矩阵。
  3. 用匈牙利算法,在这个矩阵上找到总代价最小的匹配方案。
  4. 设定一个IOU阈值(比如0.3),低于阈值的匹配直接丢弃。

为什么用IOU?因为简单、快。我记得有一次在嵌入式设备上跑SORT,CPU资源紧张得要命。如果用外观特征做匹配,光提取特征就得几十毫秒。而IOU计算就是几个除法,一帧里几百个目标也能在1毫秒内搞定。

注意:IOU匹配有个致命弱点——当目标运动速度很快时,预测框和检测框可能完全不重叠,IOU直接为0。这时候跟踪就会断掉。我在高速车辆跟踪项目中就踩过这个坑,后来不得不把IOU阈值调低,同时增大卡尔曼滤波的噪声协方差,让预测框「敢」跑远一点。

3.4 算法流程总览:一帧一帧怎么跑

好了,我们把上面这些拼起来,看看SORT在每一帧里到底干了什么。我习惯用伪代码来理解流程:

对于每一帧:
  1. 获取检测器输出的所有检测框 D
  2. 对每个已有轨迹 T_i:
     a. 用卡尔曼滤波预测 T_i 在当前帧的状态
     b. 得到预测框 P_i
  3. 计算所有 P_i 和 D_j 的 IOU,构建代价矩阵
  4. 用匈牙利算法做匹配,得到匹配对 (T_k, D_l)
  5. 对每个匹配对:
     a. 用 D_l 更新 T_k 的卡尔曼滤波器
     b. 标记 T_k 为「已匹配」
  6. 对未匹配的检测框:
     a. 创建新轨迹,初始化卡尔曼滤波器
  7. 对未匹配的轨迹:
     a. 如果连续未匹配超过阈值(如3帧),删除该轨迹
     b. 否则,保持预测状态,等待下一帧

这个流程看起来简单,但每个环节都有讲究。比如第7步的「未匹配轨迹处理」,我见过有人直接把未匹配的轨迹删掉,结果目标被短暂遮挡一下就丢了。正确的做法是给它一个「存活期」,就像给员工一个宽限期一样。

嗯,这里还要提一句:SORT的整个流程是完全在线的。它不需要看未来的帧,也不需要回看过去的帧。每一帧的处理都是独立的,这保证了它的实时性。我在实际部署时,用YOLOv3做检测器,SORT做跟踪器,在GTX 1080上能跑到60 FPS以上。

3.5 小结:SORT为什么能打?

总结一下SORT的核心思想:

  • 范式:检测+跟踪,各司其职
  • 状态估计:卡尔曼滤波,用匀速模型做预测和修正
  • 数据关联:IOU+匈牙利算法,简单粗暴但高效
  • 流程:预测→匹配→更新→创建/删除,一帧搞定

你可能会觉得:「就这?这也太简单了吧?」没错,SORT就是简单。但正是这种简单,让它成为了多目标跟踪领域的基准线。后来的DeepSORT、FairMOT等算法,都是在SORT的基础上做加法。所以,把SORT吃透,后面的路就好走了。

下一章,我会带你手撕SORT的代码实现。到时候你会发现,代码比理论还简单。