function markMovesInCamera(videoSource, moveTresh, strelOpen, strelClose) %% function markMovesInCamera(inVideo, moveTresh, strelOpen, strelClose) % This function tracks and presents moving regions in a video filmed by a % still USB camera % %% Syntax % markMovesInCamera(inVideo); % markMovesInCamera(inVideo, moveTresh); % markMovesInCamera(inVideo, moveTresh, strelOpen); % markMovesInCamera(inVideo, moveTresh, strelOpen, strelClose); % %% Description % This functions presents a figure with only moving regions of the datya % filmed by a camera. The user can control several parameters, to achive % the presentation of regions he is interested in. This function can be % though of as a mammal vision system simulation (some mammals, like dogs, % see only object that move). % %% Input arguments (defaults exist): % videoSource- vidoe data device (usually USB camera) % moveTresh- used to deetct movements. Pixels with value above this % treshold are assumed to include movements. % strelOpen- a structuring element, and integer value used to define % a structuring element dimentions, or a matrix of logicals used to % define the presneted ROI dimentions. In other worlds defines the % area around detected movements to be presented. Larger value will % resul in larger region. % strelClose- a structuring element, and integer value used to define % a structuring element dimentions, or a matrix of logicals. Those % define the speed of "aging", or hsitorical data influencue on % current figure. It defines how the ROI of previous frame infleuemce % ROI of current frame. Larger value will result in fatser aging- old % ROI data will be removed fatser. Small value will result in slow % "aging"- areas with movements in previous frames, will be preserved % and presenetd in longer period. % %% Output arguments % None. Movements are presenetd on a figure; % %% Issues & Comments % Camera is assumed to be still. % Sometimes, whole frame is detceted as moving. Seems like a camera % issue... % Function is actually a combintion of IMAQMOTION by David Tarkowski (Many % thanks and big respect to the author. See % http://www.mathworks.com/matlabcentral/fileexchange/5470-imaqmotion-image-acquisition-motion-detection % and my fuction markMovesInVideo. % %% Example % videoSource=videoinput('winvideo', 1); % moveTresh=30; % strelOpen=2; % strelClose=2; % markMovesInCamera(videoSource, moveTresh, strelOpen, strelClose); % % %% See also % IMAQMOTION % VIDEOINPUT % markMovesInVideo % %% Revision history % First version: Nikolay S. 2011-10-21. % Last update: Nikolay S. 2011-10-24. % % *List of Changes:* % %% Default parameters if nargin<4 strelClose=2; if nargin<3 strelOpen=2; if nargin<2 moveTresh=35; if nargin==0 error('MATLAB:markMovesInCamera:error',... 'Input source definition is missing.') end end end end if isnumeric(strelOpen) strelOpen = strel('disk', strelOpen , 0); elseif ~(strcmpi(class(strelOpen), 'strel') || islogical(strelOpen)) error('MATLAB:markMovesInCamera:error',... 'Bad strelOpen input.') end if isnumeric(strelClose) strelClose = strel('disk', strelClose , 0); elseif ~(strcmpi(class(strelClose), 'strel') || islogical(strelClose)) error('MATLAB:markMovesInCamera:error',... 'Bad strelClose input.') end appTitle = 'Camera Motion Detector'; %% Almost unchanged code adopted from IMAQMOTION. % My thanks and bif respect to the author: David Tarkowski. % See http://www.mathworks.com/matlabcentral/fileexchange/5470-imaqmotion-image-acquisition-motion-detection try % Make sure we've stopped so we can set up the acquisition. stop(videoSource); % Configure the video input object to continuously acquire data. triggerconfig(videoSource, 'manual'); set(videoSource, 'Tag', appTitle, 'FramesAcquiredFcnCount', 1, ... 'TimerFcn', @localFrameCallback, 'TimerPeriod', 0.1,... 'ReturnedColorSpace','rgb'); % set colormap colormap('default'),'colorcube','hsv' or ycbcr2rgb for % YUV % Check to see if this object already has an associated figure. % Otherwise create a new one. ud = get(videoSource, 'UserData'); if ~isempty(ud) && isstruct(ud) && isfield(ud, 'figureHandles') ... && ishandle(ud.figureHandles.hFigure) appdata.figureHandles = ud.figureHandles; figure(appdata.figureHandles.hFigure) else appdata.figureHandles = localCreateFigure(videoSource, appTitle); end % Store the application data the video input object needs. % prepare motion detectin, aging and region conenction parameters appdata.background = []; appdata.prevMoveMask=false(fliplr(get(videoSource,'VideoResolution'))); appdata.moveTresh=moveTresh; appdata.strelOpen=strelOpen; appdata.strelClose=strelClose; videoSource.UserData = appdata; % Start the acquisition. start(videoSource); % Avoid peekdata warnings in case it takes too long to return a frame. warning off imaq:peekdata:tooManyFramesRequested catch % Error gracefully. stop(videoSource); % delete(videoSource); error('MATLAB:imaqmotion:error', ... sprintf('IMAQMOTION is unable to run properly.\n%s', lasterr)) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function localFrameCallback(vid, event) % Executed by the videoinput object callback % to update the image display. % If the object has been deleted on us, % or we're no longer running, do nothing. if ~isvalid(vid) || ~isrunning(vid) return; end % Access our application data and parameters appdata = get(vid, 'UserData'); background = appdata.background; moveTresh=appdata.moveTresh; strelOpen=appdata.strelOpen; strelClose=appdata.strelClose; prevMoveMask=appdata.prevMoveMask; % Peek into the video stream. Since we are only interested % in processing the current frame, not every single image % frame provided by the device, we can flush any frames in % the buffer. frame = peekdata(vid, 1); if isempty(frame), return; end flushdata(vid); % First time through, a background image will be needed. if isempty(background), background = getsnapshot(vid); end I = imabsdiff(frame, background); % set(figData.hImage, 'CData', I); % Update the patch to the new level value. graylevel = graythresh(I); level = max(moveTresh, floor(100*graylevel)); currMoveMask=false(size(I, 1), size(I, 2)); % Init current movements mask nClrs=size(I, 3); % Detect movement on every color (operation on intensity/grayscale data is % also an option) for iClr=1:nClrs currMoveMask=currMoveMask | (I(:, :, iClr)>level); end % Apply "aging" to historical data via Morpohological Erode operator prevMoveMask= imerode(prevMoveMask, strelClose); % Aging is impossible if whole mask is true, prevent that. if all(prevMoveMask) prevMoveMask=false(size(prevMoveMask)); end currMoveMask= imdilate(currMoveMask, strelOpen); % Connect isolated % movement elemnets to larger regions via Morpohological Dilate operator currMoveMask=currMoveMask | prevMoveMask; % Combine previous and current masks % Crop only relevant parts of image image2Show=0*frame; currMoveMask3D=repmat(currMoveMask, [1, 1, nClrs]); image2Show(currMoveMask3D)=frame(currMoveMask3D); % While figure isn't closed... if ~ishandle(appdata.figureHandles.hFigure), stop(vid); return; end % Update the figure set(appdata.figureHandles.hImage, 'CData', image2Show); drawnow; % Update application data for next frame appdata.background = frame; appdata.prevMoveMask=currMoveMask; set(vid, 'UserData', appdata); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function localDeleteFig(fig, event) % Reset peekdata warnings. warning on imaq:peekdata:tooManyFramesRequested %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function figData = localCreateFigure(vid, figTitle) % Creates and initializes the figure. % Create the figure and axes to plot into. fig = figure('NumberTitle', 'off', 'MenuBar', 'none', ... 'Name', figTitle, 'DeleteFcn', @localDeleteFig); % Create a spot for the image object display. nbands = get(vid, 'NumberOfBands'); res = get(vid, 'ROIPosition'); himage = imagesc(rand(res(4), res(3), nbands)); % Clean up the axes. ax = get(himage, 'Parent'); set(ax, 'XTick', [], 'XTickLabel', [], 'YTick', [], 'YTickLabel', []); % Store the figure data. figData.hFigure = fig; figData.hImage = himage;