读visual object tracking -- eco (Efficient Convolution Operator (ECO) tracker.) 算法的源码,一时好奇,想自己推导一下这个cubic spline kernel的计算函数。

作者:​​Martin-danelljan​​​ ​

原来的matlab是这样写的,

function bf = cubic_spline_fourier(f, a)

% The continuous Fourier transform of a cubic spline kernel.

bf = -(- 12*a + 12*exp(-pi*f*2i) + 12*exp(pi*f*2i) + 6*a*exp(-pi*f*4i) + ...
6*a*exp(pi*f*4i) + f.*(pi*exp(-pi*f*2i)*12i) - f.*(pi*exp(pi*f*2i)*12i) + ...
a*f.*(pi*exp(-pi*f*2i)*16i) - a*f.*(pi*exp(pi*f*2i)*16i) + ...
a*f.*(pi*exp(-pi*f*4i)*4i) - a*f.*(pi*exp(pi*f*4i)*4i) - 24)./(16*f.^4*pi^4);

bf(f == 0) = 1;

首先是自己走了些弯路,不知道作者到底用的哪个cubic spline, 找了一通,最后发现是这个函数(很普通,但没找到之前让好一番好猜,再后来才发现作者提供的supplementary material中有说明),详情可参考​​wikimedia​​ :

​https://en.wikipedia.org/wiki/Bicubic_interpolation​

目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_ECO

对该函数作傅立叶变换,得到

目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_tracking_02

表达式有点乱,因为最终和作者给出的相差一个(不影响计算结果的)系数,我这里把这个系数去掉

目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_AI_03

显然前面的t相当于我们平常说的目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_VOT_04,代进去,再整理一下顺序就和作者提供的完全一样了 :-),

目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_tracking_05

另外,作者最后面加了一个负号,我看了下,如果没有这个负号,所以结果都是负值,所以必须成正数。

其实在计算时,最后只用到了函数的实部,取出来直接计算的话就是这样的

目标跟踪VOT-ECO中,cubic_spline_fourier函数推导与源码解释_VOT_06

如果要看C++源码的话,可以去这里看:​​https://github.com/nicewsyly/ECO/blob/master/ECO/interpolator.cpp​​​​

这里我把他贴出来,如下

cv::Mat interpolator::cubic_spline_fourier(cv::Mat f, float a)
{
if (f.empty())
return cv::Mat();

cv::Mat bf(f.size(), CV_32FC1), temp1(f.size(), CV_32FC1), temp2(f.size(), CV_32FC1),
temp3(f.size(), CV_32FC1), temp4(f.size(), CV_32FC1);
std::transform(f.begin<float>(), f.end<float>(), temp1.begin<float>(), mat_cos2);
std::transform(f.begin<float>(), f.end<float>(), temp2.begin<float>(), mat_cos4);

std::transform(f.begin<float>(), f.end<float>(), temp3.begin<float>(), mat_sin2);
std::transform(f.begin<float>(), f.end<float>(), temp4.begin<float>(), mat_sin4);

bf = -1 * (-12 * a * cv::Mat::ones(f.size(), CV_32FC1) + 24 * temp1 +
12 * a * temp2 + CV_PI * 24 * f.mul(temp3) +
CV_PI * a * 32 * f.mul(temp3) + CV_PI * 8 * a * f.mul(temp4) -
24 * cv::Mat::ones(f.size(), CV_32FC1));

cv::Mat L(f.size(), CV_32FC1);
cv::pow(f, 4, L);
cv::divide(bf, 16 * L * cv::pow(CV_PI, 4), bf);
bf.at<float>(bf.rows / 2, bf.cols / 2) = 1;

return bf;
}

嗯,希望看到的童鞋可以省点时间。

Latex写长公式好累,眼都花了!