2. 目标跟踪基础理论

大家好,我是你们的老朋友。今天我们来聊聊目标跟踪的数学基础。说实话,这部分内容看起来有点枯燥,但它是整个跟踪系统的骨架。我当年刚入行时,觉得这些公式太抽象,直接跳过去写代码,结果调了两个月都没调通。后来老老实实回来啃数学,才发现——嗯,真香。

2.1 目标跟踪的数学建模

目标跟踪,说白了就是回答一个问题:目标下一时刻会在哪?

我们得用数学语言把这个过程描述出来。我个人习惯把跟踪问题拆成两个部分:

  • 状态方程:描述目标怎么运动
  • 观测方程:描述我们怎么看到目标

用公式表达就是:

x_k = f(x_{k-1}) + w_k      // 状态方程
z_k = h(x_k) + v_k          // 观测方程

这里 x_k 是目标在时刻 k 的状态(位置、速度等),z_k 是我们的测量值(比如摄像头检测到的坐标)。w_k 和 v_k 分别是过程噪声和观测噪声——现实世界总有干扰,你想想看,摄像头画面抖动、目标突然加速,这些都得考虑进去。

核心要点:状态方程预测未来,观测方程修正预测。两者缺一不可。

2.2 状态估计与观测模型

有了数学模型,接下来就是怎么估计状态了。状态估计,说白了就是:根据观测数据,猜出目标最可能的状态。

我在项目中遇到过一个问题:摄像头帧率是30fps,但目标运动很快。如果只用当前帧的检测结果做跟踪,目标稍微一加速就跟丢了。这时候就需要状态估计来「补帧」。

2.2.1 状态向量设计

状态向量怎么设计?我建议至少包含:

  • 位置:x, y(图像坐标)
  • 速度:vx, vy(像素/帧)
  • 尺寸:w, h(目标框宽高)

如果你做的是三维跟踪,还得加上深度 z 和三维速度。状态向量维度越高,模型越精确,但计算量也越大。这是个 trade-off。

2.2.2 观测模型

观测模型描述的是「状态到测量值」的映射关系。最简单的就是线性观测模型:

z_k = H * x_k + v_k

其中 H 是观测矩阵。比如我们只观测位置,不观测速度,那 H 就是:

H = [[1, 0, 0, 0],
     [0, 1, 0, 0]]

这样就把四维状态映射到了二维观测空间。

避坑指南:我曾经在项目中直接用检测框中心点作为观测值,忽略了检测框的置信度。结果目标被遮挡时,检测框乱跳,跟踪直接崩了。后来我加了置信度加权,效果好了很多。

2.3 贝叶斯滤波与卡尔曼滤波基础

终于到了重头戏。贝叶斯滤波是目标跟踪的理论基石,卡尔曼滤波是它的具体实现。我当年学这部分时,老师讲了一堆概率公式,听得云里雾里。后来我自己画了个图,一下就明白了。

贝叶斯滤波与卡尔曼滤波关系图 贝叶斯滤波 预测:p(x_k | z_{1:k-1}) 更新:p(x_k | z_{1:k}) 适用于任意分布 计算复杂度高 假设线性+高斯 卡尔曼滤波 预测:x̂_k|k-1 = F * x̂_{k-1} 更新:x̂_k = x̂_k|k-1 + K * (z_k - H * x̂_k|k-1) 解析解,计算高效 要求线性系统+高斯噪声 贝叶斯滤波是理论框架,卡尔曼滤波是具体实现(线性高斯假设下)

2.3.1 贝叶斯滤波的核心思想

贝叶斯滤波就两个步骤,循环往复:

  1. 预测:根据上一时刻的状态,猜当前时刻的状态
  2. 更新:用当前时刻的观测值,修正这个猜测

用公式表达就是:

预测:p(x_k | z_{1:k-1}) = ∫ p(x_k | x_{k-1}) * p(x_{k-1} | z_{1:k-1}) dx_{k-1}
更新:p(x_k | z_{1:k}) ∝ p(z_k | x_k) * p(x_k | z_{1:k-1})

看着复杂?其实就一句话:先猜,再看,再修正。你想想看,这不就跟我们日常做判断一样吗?

2.3.2 卡尔曼滤波:贝叶斯滤波的「特供版」

贝叶斯滤波虽然优雅,但那个积分算起来太费劲了。卡尔曼老爷子聪明,他加了两个假设:

  • 系统是线性的(状态方程和观测方程都是线性函数)
  • 噪声是高斯分布(均值为0,方差已知)

在这两个假设下,所有分布都是高斯分布,积分变成了简单的矩阵运算。这就是卡尔曼滤波。

卡尔曼滤波的五个核心公式:

// 预测步骤
x̂_k|k-1 = F * x̂_{k-1}          // 状态预测
P_k|k-1 = F * P_{k-1} * F^T + Q  // 协方差预测

// 更新步骤
K = P_k|k-1 * H^T * (H * P_k|k-1 * H^T + R)^{-1}  // 卡尔曼增益
x̂_k = x̂_k|k-1 + K * (z_k - H * x̂_k|k-1)          // 状态更新
P_k = (I - K * H) * P_k|k-1                        // 协方差更新

关键理解:卡尔曼增益 K 决定了「相信预测」还是「相信观测」。K 大,更相信观测;K 小,更相信预测。这个平衡点,就是卡尔曼滤波的精髓。

2.3.3 一个简单的例子

假设我们要跟踪一个在直线上匀速运动的小球。状态是位置和速度,观测只有位置。

// 参数设置
F = [[1, dt], [0, 1]]    // 状态转移矩阵
H = [[1, 0]]             // 观测矩阵
Q = [[0.1, 0], [0, 0.1]] // 过程噪声协方差
R = [[1]]                // 观测噪声协方差

// 初始化
x̂ = [[0], [1]]           // 初始位置0,速度1
P = [[1, 0], [0, 1]]     // 初始协方差

// 每一帧执行
// 1. 预测
x̂_pred = F * x̂
P_pred = F * P * F^T + Q

// 2. 更新(假设观测到位置 z=2.1)
K = P_pred * H^T * (H * P_pred * H^T + R)^{-1}
x̂ = x̂_pred + K * (2.1 - H * x̂_pred)
P = (I - K * H) * P_pred

跑几帧之后,你会发现卡尔曼滤波估计的位置比原始观测值平滑得多。这就是滤波的效果——去噪。

注意:卡尔曼滤波假设噪声是高斯分布。如果你的传感器噪声是非高斯的(比如有离群点),卡尔曼滤波会表现得很差。这时候可以考虑使用扩展卡尔曼滤波(EKF)或无迹卡尔曼滤波(UKF)。

2.4 本章小结

这一章我们聊了目标跟踪的数学基础。从状态方程和观测方程开始,到贝叶斯滤波的理论框架,再到卡尔曼滤波的具体实现。这些东西看起来公式多,但核心思想很简单:预测 + 修正。

我个人建议,初学者先手推一遍卡尔曼滤波的五个公式,然后用 Python 写个一维跟踪的 demo。跑通了,你就能感受到滤波的魅力了。

下一章我们会聊更实用的东西——怎么用卡尔曼滤波做多目标跟踪。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。

课后练习:用 Python 实现一个一维卡尔曼滤波器,跟踪一个匀速运动的目标。观测值加上高斯噪声(标准差=2),看看滤波后的轨迹和原始观测轨迹的差异。