目標跟蹤VOT-ECO中,cubic_spline_fourier函數推導與源碼解釋

讀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


f(x) =\left\{\begin{matrix} 0 & x<-2 \\ -a x^3-5 a x^2-8 a x-4 a & -2<x\leq -1 \\ (-a-2) x^3-(a+3) x^2+1 & -1<x\leq 0 \\ (a+2) x^3-(a+3) x^2+1 & 0<x\leq 1 \\ a x^3-5 a x^2+8 a x-4 a & 1<x\leq 2 \\ 0 & x>2 \end{matrix}\right.

對該函數作傅立葉變換,得到
\frac{\sqrt{\frac{2}{\pi }} e^{-2 i t} \left(a \left(-1+e^{2 i t}\right) \left(4 i e^{i t} t+i t+i e^{2 i t} (t+3 i)+3\right)+3 e^{i t} \left(-1+e^{i t}\right) \left(i t+i e^{i t} (t+2 i)+2\right)\right)}{t^4}

表達式有點亂,因爲最終和作者給出的相差一個(不影響計算結果的)係數,我這裏把這個係數去掉

\sqrt{\frac{1}{2\pi }}

顯然前面的t相當於我們平常說的2\omega t,代進去,再整理一下順序就和作者提供的完全一樣了 :-),

\frac{1}{16\pi^4t^4}(-24 - 12 a + 12 e^{_{-2\pi i t}} + 12e^{_{2\pi i t}} + 6a e^{_{-4\pi i t}} + 6a e^{_{4\pi i t}} + 12\pi ite^{_{-2\pi i t}} - 12\pi it e^{_{2\pi i t}} + 16\pi ait e^{_{-2\pi i t}} - 16\pi ait e^{_{2\pi i t}} + 4\pi ait e^{_{-4\pi i t}} - 4\pi ait e^{_{4\pi i t}})

另外,作者最後面加了一個負號,我看了下,如果沒有這個負號,所以結果都是負值,所以必須轉成正數。
其實在計算時,最後只用到了函數的實部,取出來直接計算的話就是這樣的

\frac{1}{16\pi^4t^4}(-12a + 24cos(2\pi t) + 12a cos(4\pi t)+ 24\pi t sin(2t\pi) + 32a\pi t sin(2t\pi) + 8a\pi t sin(4t\pi) - 24)

如果要看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寫長公式好累,眼都花了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章