Feature homography based planar tracking
Example of using features2d framework for interactive video homography matching. ORB features and FLANN matcher are used. The actual tracking is implemented by PlaneTracker class.
Inspired by http://www.youtube.com/watch?v=-ZNYoL8rzPY
Video: http://www.youtube.com/watch?v=FirtmYcC0Vc
Select a textured planar object to track by drawing a box with a mouse.
Sources:
function feature_homography_track_demo(vid) % video file, and a default target to track [x,y,w,h] win = []; if nargin < 1 vid = fullfile(mexopencv.root(), 'test', 'blais.mp4'); assert(exist(vid, 'file') == 2, 'Missing video file'); if true win = [135 165 285 175]; % face else win = [136 0 366 433]; % book end elseif isempty(vid) vid = 0; end % open video feed, and get first frame cap = cv.VideoCapture(vid); pause(1); assert(cap.isOpened(), 'Failed to open video'); frame = cap.read(); assert(~isempty(frame), 'Failed to read frames'); % prepare plot paused = false; tframe = zeros(size(frame), class(frame)); % target frame + drawings hImg = imshow([frame, tframe]); % create and initialize tracker tracker = PlaneTracker(); if ~isempty(win) onRect(win); end % create ROI region selector if ~mexopencv.isOctave() onHelp(); roi = RectSelector(hImg); roi.clip = true; roi.callback = @onRect; else %HACK: RectSelector not Octave compatible %HACK: function handle to nested function not supported in Octave roi = struct('isDragging',@()false); end % listen to keyboard input if ~mexopencv.isOctave() %HACK: function handle to nested function not supported in Octave set(ancestor(hImg,'figure'), 'WindowKeyPressFcn',@onType); end % main loop while ishghandle(hImg) playing = ~paused && ~roi.isDragging(); if playing % read new frame frame = cap.read(); if isempty(frame), break; end end out = [frame, tframe]; % track and draw keypoints and boundary of target in new frame if playing tracked = tracker.track(frame); if ~isempty(tracked) tr = tracked(1); out = cv.circle(out, tr.pt1, 2, 'Color',[255 0 0]); out = cv.polylines(out, tr.quad, 'Closed',true, ... 'Color',[0 255 0], 'Thickness',2); % draw matches out = cv.line(out, ... bsxfun(@plus, tr.pt0, [size(frame,2) 0]), tr.pt1, ... 'Color',[0 0 255]); end end % display result set(hImg, 'CData',out); if playing drawnow; else pause(0.1); % slow down a bit if paused end end cap.release(); if isobject(roi), delete(roi); end % --- Callback functions --- function onRect(rect) %ONRECT Callback for ROI selector % % onRect(rect) % % ## Input % * __rect__ selected rectangle [x,y,w,h], or empty % if isempty(rect), return; end % selection must be made in left image (current frame) rect = cv.Rect.intersect(rect, [0 0 size(frame,2) size(frame,1)]); if cv.Rect.area(rect) < 1, return; end % track new target disp('New target...') tracker.clear(); tracker.addTarget(frame, rect); % draw keypoints and boundary in target frame if ~isempty(tracker.targets) t = tracker.targets(1); tframe = cv.drawKeypoints(t.image, t.kpts, 'Color',[255 0 0]); tframe = cv.rectangle(tframe, t.rect(1:2), t.rect(3:4), ... 'Color',[0 255 0], 'Thickness',2); else tframe(:) = 0; end % un-pause paused = false; end function onType(hfig, e) %ONTYPE Event handler for key press on figure switch e.Key case {'q', 'escape'} close(hfig); case 'h' onHelp(); case {'space', 'p'} disp('Toggle pause...'); paused = ~paused; case {'c', 'r'} disp('Clearing tracker...'); tracker.clear(); tframe(:) = 0; end end function onHelp() %ONHELP Display usage help dialog h = helpdlg({ 'Select object(s) to track using the mouse.' 'Hot keys:' ' q - quit' ' h - help' ' p - pause' ' c - clear targets' }); % wait for user to accept dialog set(h, 'WindowStyle','modal'); waitfor(h); end end
New target...