mosse(Minimizing the Output Sum of Squared Error)代碼解讀


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代表像素的模板座標,模板中心位置爲原點)爲:

    g(x,y)=12πσ2e(x2+y2)2σ2 \boldsymbol{g}\left( \boldsymbol{x},\boldsymbol{y} \right) =\frac{1}{2\boldsymbol{\pi \sigma }^2}\boldsymbol{e}^{-\frac{\left( \boldsymbol{x}^2+\boldsymbol{y}^2 \right)}{2\boldsymbol{\sigma }^2}} 但是爲什麼代碼中,只有e(x2+y2)2σ2\boldsymbol{e}^{-\frac{\left(\boldsymbol{x}^2+\boldsymbol{y}^2 \right)}{2\boldsymbol{\sigma}^2}}這一部分呢?------這是因爲我們要畫出高斯圖像 ,使高斯響應在我們所框的框框的中心達到最大的峯值,而12πσ2\frac{1}{2\boldsymbol{\pi \sigma}^2}裏都是常數,對我們找高斯位置並沒有影響,所以把其捨去。

  • 再者,(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,如下圖,從論文公式可以得出,當前濾波器是與前一幀的濾波器有關的,當第一幀時,其實就是求這個濾波器的初始值,η\boldsymbol{\eta }爲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就是η\boldsymbol{\eta },取值爲0~1,代表着當前幀受前一幀影響的大小,若η\boldsymbol{\eta }越小,則表示受前一幀影響就越大

  • 當第一幀進入時,我們用第一幅圖來訓練,所以Ai和Bi不用更新:Ai = eta.*Ai; Bi = eta.*Bi;

  • 將第一幀得到的濾波器Hi,用在第二幀上

  • gi是什麼呢?先知道Gi是對Hi和Fi進行點乘得到的,在對點乘的結果Gi進行反傅里葉變換,就得到gi,在論文中的公式爲:
    在這裏插入圖片描述

  • 將Gi變換到gi,是由頻域變換到空間域,空間域就是: 在這裏插入圖片描述

  • 接下來就要尋找gi的最大值所在的座標,這裏使用mean(P)和mean(Q)是爲什麼呢?------說明取得最大值的地方有很多,這裏取了一個平均值,這裏如果是一個比較簡單的場景,比如一輛飛機在藍色的天空中飛過,可能就只有一個最大值,但是如果是一個複雜場景,比如一個人在馬路上走,可能就有很多響應的最大值,所以取了一個平均值

  • 再在取最大值的點的位置,畫出一個與我們所畫的矩形框有相同大小的矩形框(通過這個新畫出來矩形框繼續去運行,直到迭代完全部的視頻幀)

  • 最後再根據我們的論文,更新Ai和Bi 在這裏插入圖片描述

  • 最後再將所更新的矩形框畫出來

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