2. 经典相关滤波跟踪器 (上)
各位同学,今天我们来聊聊相关滤波跟踪。说实话,这个方向我研究了很久。记得2015年我刚入行时,公司接了个无人机跟踪项目,目标动不动就丢。后来我把KCF调参调了一周,终于稳住了。嗯,从那以后我就对相关滤波有了感情。
相关滤波的核心思想其实很简单:在图像里找一个滤波器,让它对目标区域的响应最大,对背景的响应最小。你想想看,这不就是我们要的跟踪吗?
核心公式:相关滤波跟踪 = 频域快速计算 + 在线更新模板
2.1 MOSSE:一切的开端
MOSSE(Minimum Output Sum of Squared Error)是2010年CVPR上的工作。说实话,它真的很朴素,但效果在当时是惊艳的。
MOSSE的核心思想:
- 在频域中学习一个滤波器,使得目标区域的响应是高斯形状
- 使用最小二乘法求解,闭式解一步到位
- 在线更新:每帧用学习率融合新模板
我给大家看下MOSSE的求解过程。假设我们有一组训练样本 \( f_i \) 和期望输出 \( g_i \),我们要找的滤波器 \( h \) 满足:
# MOSSE的频域求解(伪代码)
# 初始化
H = np.zeros_like(F) # 滤波器频域表示
# 对每一帧
F = fft2(image_patch) # 目标区域做FFT
G = fft2(gaussian_label) # 高斯标签做FFT
# 更新分子和分母
A_i = conj(G) * F # 分子
B_i = conj(F) * F # 分母
# 在线更新(学习率eta=0.125)
A = eta * A_i + (1-eta) * A
B = eta * B_i + (1-eta) * B
# 当前帧的滤波器
H = A / (B + epsilon)
# 检测:相关响应图
response = ifft2(H * conj(fft2(search_patch)))
这里有个坑,我当年踩过:epsilon一定要加。不加的话,分母为0直接崩掉。我建议epsilon取1e-5到1e-8之间。
个人经验:MOSSE的更新率eta很关键。eta太大(>0.2)容易漂移,太小(<0.05)跟不上目标变化。我一般用0.125,这是论文推荐值,实际效果也确实不错。
2.2 CSK:引入核技巧
MOSSE有个问题:它只用了原始像素特征,表达能力有限。CSK(Circulant Structure of Tracking-by-detection with Kernels)在2012年解决了这个问题。
CSK的贡献主要有两点:
- 循环矩阵:利用循环移位生成大量训练样本,不用手动标注
- 核技巧:把特征映射到高维空间,提升判别能力
为什么循环矩阵这么重要?说白了,循环矩阵在频域可以对角化。这意味着原本O(n³)的矩阵求逆,变成了O(n log n)的FFT操作。你想想看,这速度提升有多大!
CSK的求解公式变成了:
# CSK的核相关滤波求解
# 核矩阵K是循环矩阵
# 在频域中求解对偶系数alpha
# 训练
k = kernel_correlation(x, x) # 自相关
alpha = fft2(y) / (fft2(k) + lambda_reg)
# 检测
k_z = kernel_correlation(z, x) # 互相关
response = ifft2(fft2(k_z) * alpha)
注意:CSK用的核是线性核或高斯核。高斯核有个超参数sigma,我建议设为目标尺寸的0.1倍左右。太小了过拟合,太大了欠拟合。
2.3 KCF:把HOG加进来
CSK虽然引入了核技巧,但特征还是原始像素。KCF(Kernelized Correlation Filters)在2014年做了两件大事:
- 多通道特征融合:把HOG特征引入相关滤波框架
- 核相关滤波的完整推导:给出了多通道情况下的闭式解
KCF的HOG特征融合,说白了就是把每个cell的梯度直方图当成一个通道。假设HOG是31维的,那我们就有了31个通道的特征图。
多通道的核相关计算:
# KCF多通道高斯核计算
def gaussian_correlation(x1, x2, sigma):
# x1, x2: 多通道特征 [C, H, W]
# 计算所有通道的平方和
x1_sq = np.sum(x1**2, axis=0)
x2_sq = np.sum(x2**2, axis=0)
# 互相关(频域计算)
x1_f = fft2(x1) # [C, H, W/2+1]
x2_f = fft2(x2)
# 逐通道相乘后求和
cross = np.real(ifft2(np.sum(x1_f * np.conj(x2_f), axis=0)))
# 高斯核
c = x1_sq + x2_sq - 2 * cross
k = np.exp(-1 / sigma**2 * np.clip(c, 0, None))
return k
我个人觉得,KCF是相关滤波跟踪的里程碑。为什么?因为它把特征工程和频域优化完美结合了。HOG特征对光照变化和形变有很好的鲁棒性,而频域计算保证了实时性。
KCF vs MOSSE vs CSK 对比
| 方法 | 特征 | 核技巧 | 速度(FPS) | 精度(OTB-50) |
|---|---|---|---|---|
| MOSSE | 原始像素 | 无 | ~600 | ~0.40 |
| CSK | 原始像素 | 高斯核 | ~300 | ~0.52 |
| KCF | HOG(31维) | 高斯核 | ~170 | ~0.73 |
看到没?KCF虽然速度比MOSSE慢了点,但精度提升了近一倍。这就是特征工程的威力。
2.4 HOG特征融合的细节
HOG特征怎么跟相关滤波结合?这里有几个关键点:
- 特征提取:对目标区域提取HOG,得到31维特征图
- 余弦窗:对特征图加余弦窗,抑制边界效应
- 频域计算:所有操作都在频域完成,保持实时性
- 尺度处理:KCF本身不支持尺度变化,需要额外处理
我曾经在项目中遇到一个问题:HOG的cell size怎么选?太小了特征维数爆炸,太大了空间信息丢失。我建议cell size取4×4或8×8,具体看目标大小。目标小就用小cell,目标大就用大cell。
避坑指南:HOG特征提取后,一定要做归一化。我见过有人直接拿原始HOG值做相关滤波,结果响应图全是噪声。归一化方法我推荐L2范数归一化,简单有效。
2.5 本章知识体系
下面我用一张图来总结本章的核心逻辑:
从这张图可以看得很清楚:MOSSE是地基,CSK加了核技巧这层楼,KCF又加了HOG特征这层楼。每一层都在前一层的基础上做了改进。
好了,本章的内容就到这里。相关滤波跟踪器的核心思想其实不复杂,但细节很多。我建议大家动手实现一遍MOSSE和KCF,代码量不大,但能帮你真正理解频域跟踪的精髓。