《Fast Traking via Spatio-Temporal Context Learning》要点整理与代码实现之一
最近读了一篇名为《Fast Tracking via Spatio-Temporal Context Learning》的论文,主要介绍了一种基于时空上下文的物体跟踪算法。在此之前,CSDN博主“zouxy09”已经写过一篇对该论文的解读http://blog.csdn.net/zouxy09/article/details/16889905。在本博文中,我没有按照原论文的思路,而是在对原文内容已经熟悉的基础上(希望读者也能在熟悉原论文后再看本博文),按照自己的思路重新归纳,主要对一些自己容易忽略的重点,或者原文中没有得到强调的逻辑关系加以整理。
几个概念:
贝叶斯框架(Bayesian framework):建立目标与其周围的区域在低层特征(像素强度值)上的统计相关性
时空上下文模型(Spatio-temporal context model):空间关系(量化为“空间上下文模型”(spatial context model))是目标及其邻域间固有的,时间关系则是通过加权累加每一历史帧(当前帧之前的所有帧)的空间关系而得到的
主要思想:
基于“贝叶斯框架”建立目标物体和其局部上下文之间的时空关系,通过这一“时空模型”计算“置信图”(confidence map),由“置信图”中似然概率最大的位置预测出新的目标位置。
1.求“时空上下文模型”
是已得到的“时空上下文模型”(Spatio-temporal context model)(其中加权累加了第t-1帧到第1帧的所有“空间上下文模型”),可用于计算本帧的“置信图”,从而得到本帧的目标位置。是在当前帧(第t帧)中新计算出来的“空间上下文模型”(spatial context model)。是由以上两个模型按权相加后得到的新“时空上下文模型”,用于在下一帧中计算其“置信图”,得到下一帧的新目标位置。是权值,是一个常数。
(1)“时空上下文模型”的初始化
对第1帧,上式显然不成立,因为我们并没有第0帧的“空间上下文模型”和“时空上下文模型”,所以在初始化时,直接令第1帧的“时空上下文模型”直接等于其“空间上下文模型”。
2.求“置信图”
置信图由上式求出,有这么几点应该注意:
- 当前帧是第t+1帧,用该式求“置信图”的目的是为了求出本帧的目标位置;
- 此时此刻手头上拥有的信息是:在上一帧中更新了的“时空上下文模型”,当前帧(第t+1帧)的像素强度值,上一帧的目标位置和目标尺度。
- 用FFT加速卷积运算
- 由于该置信图的值在每一帧中都会被更新,是不断变化的,且与时空信息有关,是从全局角度来看的,所以我将其称为“绝对置信图”,那么对应的还有“相对置信图”,在后面我会说到。在这里只需要记住,“绝对置信图”在每一次迭代中都要重新计算,是不断更新的;而“相对置信图”是不变的,是一个常值。
- 第一帧不用求该置信图,因为“绝对置信图”总是用上一帧的目标位置和尺度来求的,而在第一帧中,我们并没有第0帧的目标位置和尺度,我们初始化的直接是第1帧的目标位置和尺度,况且我们已经由初始化得到了第1帧的目标位置和尺度,也就不用由“绝对置信图”来求该帧的目标位置和尺度了。
3.求“空间上下文模型”
若已知本帧的目标位置,则在以该目标位置为中心的邻域(局部上下文)内,“置信图”可以如下建模:
这里,、和b都是常数,故其值只与目标邻域中各点相对目标位置的距离有关,因此当该邻域大小确定时,该“置信图”是一个常量矩阵,不因每一帧目标位置的变化而变化,因此我将该置信图称为“相对置信图”,意指其大小只与目标周围点到目标的相对距离有关。
以上两式用来求“空间上下文模型”,但请注意它们均没有脚标,即没有时间上下文的概念。这也就是说,所有计算利用的都是本帧自身的信息(本帧自己的目标位置、本帧自己的目标尺度、本帧自己的像素强度值等)。因此在计算“空间上下文模型”时,特别要注意,我们首先要得到本帧的目标位置和目标尺度。因此除了第1帧外,context prior model要求两次,一次用上一帧的目标位置和尺度来求(用于求本帧的目标位置),一次用本帧的目标位置和尺度来求(用于求本帧的空间上下文模型)。
算法流程:
代码实现(Matlab):
在参考了作者的matlab代码后,我按照自己画的流程图重新写了一遍,参数初始化则完全照搬了作者的。
% My implementation for STC model based tracking %% clear, clc, close all; %% fftw('planner','patient'); %% addpath('./data'); img_dir = dir('./data/*.jpg'); %% Initializaiton % constant parameter target_sz = [95, 75]; % (rows, cols) context_sz = target_sz * 2; % (rows, cols) rho = 0.075; alpha = 2.25; beta = 1; lambda = 0.25; num = 5; hamming_window = hamming(context_sz(1)) * hann(context_sz(2))'; % variable initialization target_center = [65, 161] + target_sz ./ 2; % (row, col) sigma = mean(target_sz); scale = 1; [rs, cs] = ndgrid((1:context_sz(1)) - context_sz(1)/2, (1:context_sz(2)) - context_sz(2)/2); dist = rs.^2 + cs.^2; % a 190x150 matrix conf = exp( -1 .* (sqrt(dist) ./ alpha).^beta ); conf = conf/sum(sum(conf)); % normalization conff = fft2(conf); scale_arr = zeros(num+1, 1); %% for frame = 1:numel(img_dir) % read one frame img = imread(img_dir(frame).name); im = rgb2gray(img); % compute the context prior model with the target center and sigma of the previous frame window = hamming_window .* exp(-0.5 * dist / (sigma^2)); % It should be a 190x150 matrix window = window/sum(sum(window));%normalization context_prior = compute_prior(im, target_center, context_sz, window); % using the target_center and sigma of the previous frame if frame > 1 % compute the confidence map conf_map = real(ifft2( Hstcf .* fft2(context_prior) )); % find the new target center of the current frame [row, col] = find(conf_map == max(conf_map(:)), 1); target_center = target_center - context_sz / 2 + [row, col]; % here is weird, why we should substract 'context_sz/2' from the 'target_center'? % update sigma to current frame sigma = sigma * scale; % compute the new context prior model with the target center and sigma % of the current frame window = hamming_window .* exp(-0.5 * dist / (sigma^2)); % It should be a 190x150 matrix window = window/sum(sum(window));%normalization context_prior = compute_prior(im, target_center, context_sz, window); % using the new target_center and sigma of current frame % update the confidence map of the current frame conf_map = real(ifft2( Hstcf .* fft2(context_prior) )); % update scale (you can also keep 'scale=1') % scale_arr(1:num) = scale_arr(2:end); % scale_arr(num) = max(conf_map(:)); % scale_avr = 0; % if frame > (num + 1) % for i = 1:num % scale_avr = scale_avr + sqrt(scale_arr(num + 2 - i) / scale_arr(num + 1 - i)); % end % scale = (1 - lambda) * scale + lambda * scale_avr / num; % end end % learn the spatial context model hscf = conff ./ fft2(context_prior); % update spatio_temporal context model if frame == 1 Hstcf = hscf; else Hstcf = (1-rho) * Hstcf + rho * hscf; end %visualization target_sz([2,1]) = target_sz([2,1])*scale;% update object size rect_position = [target_center([2,1]) - (target_sz([2,1])/2), (target_sz([2,1]))]; imagesc(uint8(img)) colormap(gray) rectangle('Position',rect_position,'LineWidth',4,'EdgeColor','r'); hold on; text(5, 18, strcat('#',num2str(frame)), 'Color','y', 'FontWeight','bold', 'FontSize',20); set(gca,'position',[0 0 1 1]); pause(0.001); hold off; drawnow; end %% The end
代码目前还存在一些问题有待讨论:
- 自己写的尺度更新的部分不能工作,因此我把他注释掉了,现在只能工作于单尺度(scale=1);
- conf_map = real(ifft2( Hstcf .* fft2(context_prior) )) 这句中,ifft2的结果仍是复数,因此作者取了其实部用于后续计算,为什么ifft2的结果是复数?为什么作者只取其实部而不是取其模?
- “hamming window”对结果的影响有多大;对原图的像素强度值作者也做了normalization,如果把这些都去掉,对结果影响有多大,这还有待测试
- 目标位置初始化:target_center = [65, 161] + target_sz ./ 2;目标位置更新:target_center = target_center - context_sz / 2 + [row, col],加上target_sz/2和减去context_sz/2显然是作者有意而为之的,意义何在?