Code covered by the BSD License  

Highlights from
Detect & Present movements. Mammal Visual system

image thumbnail
from Detect & Present movements. Mammal Visual system by Nikolay S.
This function tracks and presents moving regions in real time from still camera or file.

markMovesInCamera(videoSource, moveTresh, strelOpen, strelClose)
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', []);

title( sprintf('Showing areas of movement. \nTo finish close figure.'),...
    'FontSize', 17);
% Store the figure data.
figData.hFigure = fig;
figData.hImage = himage;

Contact us