Permalink
Browse files

Add a new feature: automatically detecting an object using background…

… subtraction. Now the object does not need to be present in the first frame. However, a background image is required.
  • Loading branch information...
TheMrtN committed Sep 11, 2011
1 parent f5e0c6e commit 02ce59101a2cc493ab6795a2a1ed5b10c8e6f5f4
Showing with 380 additions and 100 deletions.
  1. +40 −10 run_TLD.m
  2. +71 −0 tld/tldExample2.m
  3. +124 −0 tld/tldWaitForObject.m
  4. +14 −90 utils/determine_initial_bb.m
  5. +38 −0 utils/get_background_image.m
  6. +93 −0 utils/get_bb_backgroundsubtraction.m
View
@@ -25,9 +25,11 @@
% Feature flags
remember_fps = 0; % toggle remembering the fps in a global vector called 'fps'
save_object = 0; % toggle saving the picture inside the bounding box of every frame
+detect_object = 0; % toggle detecting if an object appears in the scene
% Input / output settings
-opt.source = struct('camera',0,'input','_input/','bb0',[]); % camera/directory swith, directory_name, initial_bounding_box (if empty, it will be selected by the user)
+input = '_input/'; % motorbike example
+opt.source = struct('camera',0,'input',input,'bb0',[]); % camera/directory swith, directory_name, initial_bounding_box (if empty, it will be selected by the user)
opt.output = '_output/'; mkdir(opt.output); % output directory that will contain bounding boxes + confidence
if save_object
opt.object = '_object/'; mkdir(opt.object); delete([opt.object '*.png']); % output directory that will contain the images inside the bounding box of every frame
@@ -41,14 +43,15 @@
update_detector = 1; % online learning on/off, of 0 detector is trained only in the first frame and then remains fixed
opt.plot = struct('pex',1,'nex',1,'dt',1,'confidence',1,'target',1,'replace',0,'drawoutput',3,'draw',0,'pts',1,'help', 0,'patch_rescale',1,'save',0,'save_object',save_object);
-% If we don't use camera input, the init.txt does not exist and there is a
-% background directory, determine the bounding box of the input by making a
-% init.txt with the bounding box of the biggest blob in the first frame.
+% If we don't wait for the object to appear, we don't use camera input, the
+% init.txt does not exist and there is a background directory, determine
+% the bounding box of the input by making a init.txt with the bounding box
+% of the biggest blob in the first frame.
% This requires a picture of the background in the folder [opt.source.input
% 'background/'].
-if ~opt.source.camera && ~exist([opt.source.input 'init.txt'], 'file') && exist([opt.source.input 'background/'], 'dir')
+if ~detect_object && ~opt.source.camera && ~exist([opt.source.input 'init.txt'], 'file') && exist([opt.source.input 'background/'], 'dir')
determine_initial_bb(opt.source.input, min_win);
-end; % else, the bounding box is determined by the user.
+end; % else, the bounding box is determined by the user or the existing init.txt is used.
% Do-not-change -----------------------------------------------------------
@@ -67,10 +70,37 @@
fps = [];
end;
-%profile on;
-[bb,conf] = tldExample(opt);
-%profile off;
-%profile viewer;
+% If detect_object is disabled, run TLD as usual.
+bb = []; conf = [];
+if ~detect_object
+ %profile on;
+ [bb,conf] = tldExample(opt);
+ %profile off;
+ %profile viewer;
+else % If detect_object is enabled.
+ % Play the frame sequence until an object of sufficient size is
+ % detected.
+ [i, initialBB] = tldWaitForObject(opt);
+ % If it returned a valid index and bounding box, run TLD.
+ if i ~= -1 && ~isempty(initialBB)
+ % Save the handle, but clear the rest of the tld variable.
+ global tld;
+ handle = -1;
+ if isfield(tld,'handle')
+ handle = tld.handle;
+ end;
+ clear global tld;
+
+ % Run TLD.
+ [bb, conf] = tldExample2(opt, i, initialBB, handle);
+ elseif i == 1 && isempty(initialBB) % Something went wrong during initialization.
+ % Run TLD as usual.
+ disp(['Notification from ' mfilename ': intialization of automatically detecting an object failed. Starting TLD as usual.']);
+ [bb,conf] = tldExample(opt);
+ else
+ disp(['Notification from ' mfilename ': waited for an object to appear, but reached the end of the frame sequence before we could find one.']);
+ end;
+end;
% Save results ------------------------------------------------------------
dlmwrite([opt.output '/tld.txt'],[bb; conf]');
View
@@ -0,0 +1,71 @@
+% Copyright 2011 Zdekek Kalal
+% File created by Maarten Somhorst.
+%
+% This file is not part of the original TLD. However, most of the lines are
+% copied from tldExample or other functions (mentioned in the comments).
+%
+% TLD is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% TLD is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with TLD. If not, see <http://www.gnu.org/licenses/>.
+%
+% tldExample2(opt, startIndex, bb, handle) works a lot like tldExample(opt),
+% but is able to start at the frame determined by the startIndex parameter.
+% Furthermore, an existing handle can be given as a parameter.
+
+function [bb, conf] = tldExample2(opt, startIndex, initialBB, handle)
+
+% Check index.
+if startIndex <= 0
+ disp(['Warning in ' mfilename ': start index cannot be smaller than or equal to zero. An index of one is assumed.']);
+ startIndex = 1;
+end;
+% Check initialBB.
+if size(initialBB,1) ~= 4
+ disp(['Error in ' mfilename ': intial bounding box has a unusual size. Cannot initialize TLD.']);
+ bb = []; conf = [];
+ return;
+end;
+
+global tld; % holds results and temporal variables
+
+% If a valid handle is given, save it.
+if handle ~= -1
+ tld.handle = handle;
+end;
+
+% INITIALIZATION ----------------------------------------------------------
+
+% From: tldInitSource
+opt.source.files = img_dir(opt.source.input);
+opt.source.files = opt.source.files(startIndex:end); % Filter the relevant frames.
+opt.source.idx = 1:length(opt.source.files);
+% -------------------
+
+figure(2);
+
+% From: tldInitFirstFrame
+opt.source.im0 = img_get(opt.source, opt.source.idx(1));
+opt.source.bb = initialBB;
+% -----------------------
+
+tld = tldInit(opt,tld); % train initial detector and initialize the 'tld' structure
+tld = tldDisplay(0,tld); % initialize display
+
+% RUN-TIME ----------------------------------------------------------------
+
+tld = tldExampleLoop(tld);
+
+% RETURN RESULTS ----------------------------------------------------------
+
+bb = tld.bb; conf = tld.conf;
+
+end
View
@@ -0,0 +1,124 @@
+% Copyright 2011 Zdekek Kalal
+% File created by Maarten Somhorst
+%
+% This file is not part of the original TLD. However, most of the lines are
+% copied from tldExample or other functions (mentioned in the comments).
+%
+% TLD is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version.
+%
+% TLD is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with TLD. If not, see <http://www.gnu.org/licenses/>.
+%
+% tldWaitForObject(opt) processes and displays each frame until an object
+% is detect. Then it returns the frame index and the bounding box.
+%
+% If no object is found and the last frame is processed, an index of -1 and
+% an empty bounding box is returned. If something went wrong with the
+% background image, the index is set to 1 and an empty bounding box is
+% returned.
+
+function [index, bb] = tldWaitForObject(opt)
+
+% INITIALIZATION ----------------------------------------------------------
+index = -1;
+bb = [];
+
+global tld;
+opt.source = tldInitSource(opt.source);
+
+figure(2); set(2,'KeyPressFcn', @handleKey); % open figure for display of results
+finish = 0;
+function handleKey(dummy1,dummy2), finish = 1; fprintf('Execution interrupted by keypress.\n'); end % by pressing any key, the process will exit
+
+% From: tldInitFirstFrame
+opt.source.im0 = img_get(opt.source,opt.source.idx(1));
+% -----------------------
+
+% From: tldInit
+if ~isempty(tld);
+ handle = tld.handle;
+ tld = opt;
+ tld.handle = handle;
+else
+ tld = opt;
+end
+
+tld.img = cell(1,length(tld.source.idx));
+tld.img{1} = tld.source.im0;
+% -------------
+
+% Load background picture.
+bg = get_background_image(tld.source.input);
+if isempty(bg)
+ disp(['Error in ' mfilename ': no background image found. Returning.']);
+ index = 1;
+ return;
+end;
+
+% Check if the first frame already contains the object. If so, return.
+bb = get_bb_backgroundsubtraction(bg, tld.img{1}.input);
+if ~isempty(bb) && min(bb_size(bb)) >= tld.model.min_win
+ index = 1;
+ return;
+end;
+
+% From: tldDisplay
+tld.handle = imshow(tld.img{1}.input,'initialmagnification','fit');
+set(gcf,'MenuBar','none','ToolBar','none','color',[0 0 0]);
+set(gca,'position',[0 0 1 1]);
+set(tld.handle,'cdata',tld.img{1}.input);
+hold on;
+set(gcf,'Position',[100 100 [640 360]]);
+% ----------------
+
+
+% RUN-TIME ----------------------------------------------------------------
+
+for i = 2:length(tld.source.idx) % for every frame
+
+ % From: tldProcessFrame
+ tld.img{i} = img_get(tld.source,i); % grab frame
+ % ---------------------
+
+ % Check if this frame contains an object. If so, return.
+ bb = get_bb_backgroundsubtraction(bg, tld.img{i}.input);
+ if ~isempty(bb) && min(bb_size(bb)) >= tld.model.min_win
+ index = i;
+ return;
+ end;
+
+ % From: tldDisplay
+ h = get(gca,'Children'); delete(h(1:end-1));
+ img = tld.img{i}.input; % draw image
+ set(tld.handle,'cdata',img); hold on;
+ drawnow;
+ tic;
+ % ----------------
+
+ if finish % finish if any key was pressed
+ if tld.source.camera
+ stoppreview(tld.source.vid);
+ closepreview(tld.source.vid);
+ close(1);
+ end
+ close(2);
+ return;
+ end
+
+ if tld.plot.save == 1
+ img = getframe;
+ imwrite(img.cdata,[tld.output num2str(i,'%05d') '.png']);
+ end
+
+end
+
+end
+
Oops, something went wrong.

0 comments on commit 02ce591

Please sign in to comment.