mosse論文解讀:https://blog.csdn.net/fjswcjswzy/article/details/106172434
mosse作爲使用相關濾波進行目標跟蹤的鼻祖,必須得把這玩意弄明白才能進行接下來的研究,我就從代碼的角度,一行一行理解代碼,保證弄得一清二楚。此文的代碼爲matlab,其他語言類似
步驟一: 讀取視頻幀
首先,要做的事將視頻幀讀入,代碼應該比較好理解
datadir = '../data/';
dataset = 'Surfer';
path = [datadir dataset];
img_path = [path '/img/'];
D = dir([img_path, '*.jpg']);
seq_len = length(D(not([D.isdir])));
if exist([img_path num2str(1, '%04i.jpg')], 'file'),
img_files = num2str((1:seq_len)', [img_path '%04i.jpg']);
else
error('No image files found in the directory.');
end
步驟二:在第一幀中選擇要跟蹤的目標
在把視頻幀讀入後,就要在第一幀中用矩形框 選出我們要跟蹤的目標,並且找出所選矩形框的中心center
im = imread(img_files(1,:));
f = figure('Name', 'Select object to track'); imshow(im);
rect = getrect;
close(f); clear f;
center = [rect(2)+rect(4)/2 rect(1)+rect(3)/2];
這裏我們的第一幀和要跟蹤的目標如下圖:
步驟三:畫出高斯圖像
畫出高斯的代碼爲:
sigma = 100;
gsize = size(im);
[R,C] = ndgrid(1:gsize(1), 1:gsize(2));
g = gaussC(R,C, sigma, center);
g = mat2gray(g);
這裏高斯濾波器的函數爲:
function val = gaussC(x, y, sigma, center)
xc = center(1);
yc = center(2);
exponent = ((x-xc).^2 + (y-yc).^2)./(2*sigma);
val = (exp(-exponent));
-
這裏我們使用的圖片大小是360x480 ,所以R和C都是大小爲360x480的矩陣,
-
將R,C, sigma,center當做參數傳入gaussC函數,注意這裏的高斯做了一些改變,正常來說二維高斯曲面的公式(x,y代表像素的模板座標,模板中心位置爲原點)爲:
但是爲什麼代碼中,只有這一部分呢?------這是因爲我們要畫出高斯圖像 ,使高斯響應在我們所框的框框的中心達到最大的峯值,而裏都是常數,對我們找高斯位置並沒有影響,所以把其捨去。
-
再者,(x-xc).^2 + (y-yc).^2,爲什麼要減去xc和yc呢?-------這是爲了能讓峯值中心移動到我們所框出的框框的中心位置,因爲我們如果沒有減去xc和yc,那麼峯值中心就在原點位置,如下圖:
但是,如果減去xc和yc,那麼就如下圖:
-
這裏g = mat2gray(g)實現圖像矩陣的歸一化操作。所謂”歸一化”就是使矩陣的每個元素的值都在0和1之間。
步驟四:對第一幀圖像得到一個初始濾波器
if (size(im,3) == 3)
img = rgb2gray(im);
end
img = imcrop(img, rect);
g = imcrop(g, rect);
G = fft2(g);
height = size(g,1);
width = size(g,2);
fi = preprocess(imresize(img, [height width]));
Ai = (G.*conj(fft2(fi)));
Bi = (fft2(fi).*conj(fft2(fi)));
這裏預處理函數preprocess爲:
function img = preprocess(img)
[r,c] = size(img);
win = window2(r,c,@hann);
eps = 1e-5;
img = log(double(img)+1);
img = (img-mean(img(:)))/(std(img(:))+eps);
img = img.*win;
end
- 首先將彩色圖片轉成灰度圖像
- 再將原始圖片和對原始圖片所畫出的高斯圖像 按我們所框的大小和位置切割下來
- 再對所切割下來的高斯圖像做二維傅里葉變換 並將其賦值給G
- 再對所切割下來的原始圖片進行預處理,所得的結果賦予fi
- 預處理的作用是:使用對數函數對像素值進行轉換,該函數有助於解決低對比度照明情況。 像素值被歸一化爲平均值爲0.0,範數爲1.0。 最後,將圖像乘以餘弦窗,該餘弦窗將邊緣附近的像素值逐漸減小爲零。 這還有一個好處,就是可以將更多的重點放在目標的中心附近。
- 這時候可以得到得到Ai 和 Bi,分別對應論文中的Ai 和 Bi,如下圖,從論文公式可以得出,當前濾波器是與前一幀的濾波器有關的,當第一幀時,其實就是求這個濾波器的初始值,爲1:
- 當然這個初始濾波器是非常理想化的,相當於只有一個樣本,對於一個樣本,結果是過擬合的,爲了去除這種過擬合,我們需要更多的樣本,該怎麼做呢?-----對圖片進行旋轉
第五步:隨機旋轉框內的圖像,並且得到訓練集
N = 128;
for i = 1:N
fi = preprocess(rand_warp(img));
Ai = Ai + (G.*conj(fft2(fi)));
Bi = Bi + (fft2(fi).*conj(fft2(fi)));
end
這裏rand_warp(img)函數爲:
function img = rand_warp(img)
a = -180/16;
b = 180/16;
r = a + (b-a).*rand;
sz = size(img);
scale = 1-0.1 + 0.2.*rand;
% trans_scale = randi([-4,4], 1, 1);
img = imresize(imresize(imrotate(img, r), scale), [sz(1) sz(2)]);
- 這裏對所框出的圖像進行隨機旋轉變換(變換幅度比較小),這樣就產生了128張訓練集樣本,部分樣本如下圖:
- 將新的Ai和Bi加到原始的Ai和Bi上,相當於對原始的Ai和Bi進行一個修正
步驟六:在線訓練
在線訓練的意思就是根據每一幀得到的結果進行修正反饋更新。代碼如下:
eta = 0.125;
fig = figure('Name', 'MOSSE');
mkdir(['results_' dataset]);
for i = 1:size(img_files, 1)
img = imread(img_files(i,:));
im = img;
if (size(img,3) == 3)
img = rgb2gray(img);
end
if (i == 1)
Ai = eta.*Ai;
Bi = eta.*Bi;
else
Hi = Ai./Bi;
fi = imcrop(img, rect);
fi = preprocess(imresize(fi, [height width]));
gi = uint8(255*mat2gray(ifft2(Hi.*fft2(fi))));
maxval = max(gi(:));
[P, Q] = find(gi == maxval);
dx = mean(P)-height/2;
dy = mean(Q)-width/2;
rect = [rect(1)+dy rect(2)+dx width height];
fi = imcrop(img, rect);
fi = preprocess(imresize(fi, [height width]));
Ai = eta.*(G.*conj(fft2(fi))) + (1-eta).*Ai;
Bi = eta.*(fft2(fi).*conj(fft2(fi))) + (1-eta).*Bi;
end
% visualization
text_str = ['Frame: ' num2str(i)];
box_color = 'green';
position=[1 1];
result = insertText(im, position,text_str,'FontSize',15,'BoxColor',...
box_color,'BoxOpacity',0.4,'TextColor','white');
result = insertShape(result, 'Rectangle', rect, 'LineWidth', 3);
imwrite(result, ['results_' dataset num2str(i, '/%04i.jpg')]);
imshow(result);
end
-
論文中給出的公式是:
-
這裏eta就是,取值爲0~1,代表着當前幀受前一幀影響的大小,若越小,則表示受前一幀影響就越大
-
當第一幀進入時,我們用第一幅圖來訓練,所以Ai和Bi不用更新:Ai = eta.*Ai; Bi = eta.*Bi;
-
將第一幀得到的濾波器Hi,用在第二幀上
-
gi是什麼呢?先知道Gi是對Hi和Fi進行點乘得到的,在對點乘的結果Gi進行反傅里葉變換,就得到gi,在論文中的公式爲:
-
將Gi變換到gi,是由頻域變換到空間域,空間域就是:
-
接下來就要尋找gi的最大值所在的座標,這裏使用mean(P)和mean(Q)是爲什麼呢?------說明取得最大值的地方有很多,這裏取了一個平均值,這裏如果是一個比較簡單的場景,比如一輛飛機在藍色的天空中飛過,可能就只有一個最大值,但是如果是一個複雜場景,比如一個人在馬路上走,可能就有很多響應的最大值,所以取了一個平均值
-
再在取最大值的點的位置,畫出一個與我們所畫的矩形框有相同大小的矩形框(通過這個新畫出來矩形框繼續去運行,直到迭代完全部的視頻幀)
-
最後再根據我們的論文,更新Ai和Bi
-
最後再將所更新的矩形框畫出來