Contents
Dense Optical Flow
Demo shows how to compute the optical flow for all the points in the frame using cv.calcOpticalFlowFarneback.
OpenCV provides an algorithm to find the dense optical flow. It is based on Gunner Farneback's algorithm which is explained in "Two-Frame Motion Estimation Based on Polynomial Expansion" by Gunner Farneback in 2003.
Sources:
function opt_flow_demo() % Prepare video source if true vid = 0; elseif mexopencv.require('vision') vid = fullfile(toolboxdir('vision'), 'visiondata', 'visiontraffic.avi'); %cap.PosFrames = 80; % skip first few seconds with no motion else vid = fullfile(mexopencv.root(), 'test', '768x576.avi'); end cap = createVideoCapture([], 'chess'); assert(cap.isOpened(), 'Could not initialize capturing'); % Grab first frame frame = cap.read(); assert(~isempty(frame), 'Failed to read frame'); prev = cv.cvtColor(frame, 'RGB2GRAY'); outGlitch = []; % Plot hImg = imshow(repmat(frame, [2 2])); title('Optical Flow') % Main loop while ishghandle(hImg) % Grab next frame frame = cap.read(); if isempty(frame), break; end next = cv.cvtColor(frame, 'RGB2GRAY'); if isempty(outGlitch), outGlitch = frame; end % Calculate dense optical flow flow = cv.calcOpticalFlowFarneback(prev, next, ... 'Levels',3, 'WinSize',15, 'Iterations',3, 'PolySigma',1.2); % Visualize optical flow outField = draw_vector_field(frame, flow); outGlitch = warp_flow(outGlitch, flow); outFlow1 = draw_flow_hsv(flow); outFlow2 = draw_flow_rgb(flow); % Display concatenated results set(hImg, 'CData',[outField, outGlitch; outFlow1, outFlow2]); drawnow; % Next iteration prev = next; end cap.release(); end
Warning: Image is too big to fit on screen; displaying at 67%
Helper functions
function img = draw_vector_field(img, flow, step, clr) %DRAW_FLOW Vector field flow visualization if nargin < 3, step = 2^4; end if nargin < 4, clr = [0 255 0]; end % vector field grid sz = size(flow); if true xstep = step/2:step:sz(2); ystep = step/2:step:sz(1); else xstep = round(linspace(1, sz(2), 40)); ystep = round(linspace(1, sz(1), 40)); end [X,Y] = meshgrid(xstep, ystep); % draw arrows (velocity vectors) %TODO: cv.arrowedLine if true % vectorized implementation XY = [X(:) Y(:)]; UV = reshape(permute(flow(ystep,xstep,:), [3 1 2]), 2, []).'; img = cv.circle(img, XY, 1, 'Color',clr, 'Thickness','Filled'); img = cv.line(img, XY, round(XY+UV), 'Color',clr); else % double-loops, much slower for x=xstep for y=ystep xy = [x y]; uv = [flow(y,x,1) flow(y,x,2)]; img = cv.circle(img, xy, 1, 'Color',clr, 'Thickness','Filled'); img = cv.line(img, xy, round(xy+uv), 'Color',clr); end end end end function img = draw_flow_hsv(flow) %DRAW_FLOW_HSV Flow visualization using HSV colorspace % map its direction to Hue value, and its magnitude to Value plane [ang, mag] = cart2pol(flow(:,:,1), flow(:,:,2)); % ang in [-pi,pi] if mexopencv.isOctave() %HACK: RAD2DEG not implemented in Octave ang = (ang + pi) * (180 / pi); else ang = rad2deg(ang + pi); end % create HSV image for flow visualization % (8-bit: 0 <= H <= 360/2, 0 <= S,V <= 255) img = zeros([size(flow,1) size(flow,2) 3], 'uint8'); img(:,:,1) = ang / 2; img(:,:,2) = 255; if true img(:,:,3) = min(mag*4, 255); else img(:,:,3) = cv.normalize(mag, ... 'NormType','MinMax', 'Alpha',0, 'Beta',255); end % convert to RGB image img = cv.cvtColor(img, 'HSV2RGB'); end function img = draw_flow_hsv_(flow) %DRAW_FLOW_HSV_ Flow visualization using HSV colorspace [mag, ang] = cv.cartToPolar(flow(:,:,1), -flow(:,:,2), 'Degrees',true); mag = cv.normalize(mag, 'Alpha',0, 'Beta',1, 'NormType','MinMax'); hsv = cat(3, ang, mag); hsv(:,:,3) = 1; img = cv.cvtColor(hsv, 'HSV2RGB'); img = uint8(255 * img); end function img = draw_flow_rgb(flow) %DRAW_FLOW_RGB Flow visualization using RGB colorspace dMax = max(abs(flow(:))); % max displacement img = bsxfun(@times, flow, cat(3,1,-1)); % U, -V img = (img - (-dMax)) / (dMax - (-dMax)); % map values img(:,:,3) = 0; img = uint8(255 * img); end function img = warp_flow(img, flow) %WARP_FLOW Flow glitch flow = -flow; flow(:,:,1) = bsxfun(@plus, flow(:,:,1), 0:size(flow,2)-1); flow(:,:,2) = bsxfun(@plus, flow(:,:,2), (0:size(flow,1)-1).'); img = cv.remap(img, flow, 'Interpolation','Area'); end