讀visual object tracking -- eco (Efficient Convolution Operator (ECO) tracker.) 算法的源碼,一時好奇,想自己推導一下這個cubic spline kernel的計算函數。
作者:Martin-danelljan 原項目地址:https://github.com/martin-danelljan/ECO
原來的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, 找了一通,最後發現是這個函數(很普通,但沒找到之前讓好一番好猜),詳情可參考wikimedia :
https://en.wikipedia.org/wiki/Bicubic_interpolation
對該函數作傅立葉變換,得到
表達式有點亂,因爲最終和作者給出的相差一個(不影響計算結果的)係數,我這裏把這個係數去掉
顯然前面的t相當於我們平常說的,代進去,再整理一下順序就和作者提供的完全一樣了 :-),
另外,作者最後面加了一個負號,我看了下,如果沒有這個負號,所以結果都是負值,所以必須轉成正數。
其實在計算時,最後只用到了函數的實部,取出來直接計算的話就是這樣的
如果要看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寫長公式好累,眼都花了!