Lucas-Kanade Homography Tracker
Lucas-Kanade sparse optical flow demo. Uses cv.goodFeaturesToTrack for track initialization and back-tracking for match verification between frames. Finds homography between reference and current views.
Sources:
Contents
Options
Parameters for corner detection and flow computation
shi_params = {'MaxCorners',1000, 'QualityLevel',0.01, 'MinDistance',8, ... 'BlockSize',19}; lk_params = {'WinSize',[19 19], 'MaxLevel',2, ... 'Criteria',struct('type','Count+EPS', 'maxCount',10, 'epsilon',0.03)};
Video
Prepare video source
if true vid = 0; elseif true vid = fullfile(mexopencv.root(), 'test', '768x576.avi'); elseif mexopencv.require('vision') vid = fullfile(toolboxdir('vision'), 'visiondata', 'visiontraffic.avi'); end cap = createVideoCapture([], 'chess'); assert(cap.isOpened(), 'Failed to initialize capturing');
First frame
Grab first frame
frame0 = cap.read(); assert(~isempty(frame0), 'Failed to read frame'); sz = [size(frame0,2), size(frame0,1)]; % [width,height]
Initialize
% Plot hImg = imshow(frame0); title('Lucas-Kanade homography tracker') % UI widgets to control app state algs = {'0', 'Ransac', 'LMedS', 'Rho'}; hBtn = uicontrol('Style','pushbutton', 'Position',[20 20 120 20], ... 'String','Start tracking', 'Callback',@(o,~) set(o, 'Enable','off')); hCB = uicontrol('Style','popupmenu', 'Position',[140 20 120 20], ... 'String',algs, 'Value',2);
Main loop
p0 = {}; % stores points to track while ishghandle(hImg) % Grab next frame frame = cap.read(); if isempty(frame), break; end next = cv.cvtColor(frame, 'RGB2GRAY'); out = frame; if ~isempty(p0) % track points in forward and backward direction, and check trace p2 = cv.calcOpticalFlowPyrLK(prev, next, p1, lk_params{:}); p1r = cv.calcOpticalFlowPyrLK(next, prev, p2, lk_params{:}); good = cellfun(@(a,b) max(abs(a - b)), p1, p1r) < 1.0; % keep good matches p0 = p0(good); p1 = p2(good); prev = next; % next iteration str = sprintf('track count: %d', numel(p1)); % we need at least 4 pairs of points to estimate homography if numel(p1) < 4 p0 = {}; continue; end % compute perspective transformation, and apply it on reference image % (homography between ref points and their currently tracked locations) [H, inliers] = cv.findHomography(p0, p1, ... 'Method',algs{get(hCB, 'Value')}, 'RansacReprojThreshold',10.0); overlay = cv.warpPerspective(frame0, H, 'DSize',sz); out = cv.addWeighted(out,0.5, overlay,0.5, 0.0); % draw points correspondances (inliers/outliers used in estimating H) inliers = logical(inliers); out = cv.line(out, p0(inliers), p1(inliers), 'Color',[0 128 0]); out = cv.line(out, p0(~inliers), p1(~inliers), 'Color',[128 0 0]); out = cv.circle(out, p1(inliers), 2, 'Thickness','Filled', 'Color',[0 255 0]); out = cv.circle(out, p1(~inliers), 2, 'Thickness','Filled', 'Color',[255 0 0]); else % detect and show corners p1 = cv.goodFeaturesToTrack(next, shi_params{:}); str = sprintf('feature count: %d', numel(p1)); if ~isempty(p1) out = cv.circle(out, p1, 2, 'Thickness','Filled', 'Color',[0 0 255]); end end % display points count out = cv.putText(out, str, [20 20], ... 'FontScale',0.5, 'Color',[255 255 0], 'LineType','AA'); % check if track button was clicked if strcmp(get(hBtn, 'Enable'), 'off') % save reference frame, and initialize reference points to track frame0 = frame; p0 = cv.goodFeaturesToTrack(next, shi_params{:}); if ~isempty(p0) % init points and gray image updated each iteration while tracking p1 = p0; prev = next; end set(hBtn, 'Enable','on'); end % Display result set(hImg, 'CData',out); drawnow; end cap.release();