function imaqmotion(obj)
%IMAQMOTION Create an image acquisition motion detector.
%
% IMAQMOTION(OBJ) creates a live image acquisition motion detection
% UI by acquiring data from video input object OBJ and displaying any
% motion in the image stream.
%
% Note, OBJ is re-configured to continuously acquire data in order to
% set it up for detecting motion.
%
% Example:
% % Construct a video input object and a motion display.
% obj = videoinput('winvideo', 1);
% imaqmotion(obj)
%
% See also VIDEOINPUT.
% CP 4-13-04
% Copyright 2004 The MathWorks, Inc.
% Unique name for the UI.
appTitle = 'Image Acquisition Motion Detector';
try
% Make sure we've stopped so we can set up the acquisition.
stop(obj);
% Configure the video input object to continuously acquire data.
triggerconfig(obj, 'manual');
set(obj, 'Tag', appTitle, 'FramesAcquiredFcnCount', 1, ...
'TimerFcn', @localFrameCallback, 'TimerPeriod', 0.1);
% Check to see if this object already has an associated figure.
% Otherwise create a new one.
ud = get(obj, '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(obj, appTitle);
end
% Store the application data the video input object needs.
appdata.background = [];
obj.UserData = appdata;
% Start the acquisition.
start(obj);
% Avoid peekdata warnings in case it takes too long to return a frame.
warning off imaq:peekdata:tooManyFramesRequested
catch
% Error gracefully.
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.
appdata = get(vid, 'UserData');
background = appdata.background;
% 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
% Update the figure and our application data.
localUpdateFig(vid, appdata.figureHandles, frame, background);
appdata.background = frame;
set(vid, 'UserData', appdata);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localUpdateFig(vid, figData, frame, background)
% Update the figure display with the latest data.
% If the figure has been destroyed on us, stop the acquisition.
if ~ishandle(figData.hFigure),
stop(vid);
return;
end
% Plot the results.
I = imabsdiff(frame, background);
set(figData.hImage, 'CData', I);
% Update the patch to the new level value.
graylevel = graythresh(I);
level = max(0, floor(100*graylevel));
xpatch = [0 level level 0];
set(figData.hPatch, 'XData', xpatch)
drawnow;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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', []);
% Create the motion detection bar before hiding the figure.
[hPatch, hLine] = localCreateBar(ax);
set(fig, 'HandleVisibility', 'off');
% Store the figure data.
figData.hFigure = fig;
figData.hImage = himage;
figData.hPatch = hPatch;
figData.hLine = hLine;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [hPatch, hLine] = localCreateBar(imAxes)
% Creates and initializes the bar display.
% Configure the bar axes.
barAxes = axes('XLim',[0 100], 'YLim',[0 1], 'Box','on', ...
'Units','Points', 'XTickMode','manual', 'YTickMode','manual', ...
'XTick',[], 'YTick',[], 'XTickLabelMode', 'manual', ...
'XTickLabel', [], 'YTickLabelMode', 'manual', 'YTickLabel', []);
% Align the bar axes with the image axes.
oldImUnits = get(imAxes, 'Units');
set(imAxes, 'Units', 'points')
imPos = get(imAxes, 'Position');
set(imAxes, 'Units', oldImUnits)
oldRootUnits = get(0,'Units');
set(0, 'Units', 'points');
screenSize = get(0, 'ScreenSize');
set(0, 'Units', oldRootUnits);
pointsPerPixel = 72/get(0, 'ScreenPixelsPerInch');
width = 360 * pointsPerPixel;
height = 75 * pointsPerPixel;
pos = [screenSize(3)/2-width/2 screenSize(4)/2-height/2 width height];
axPos = [1 .3 .9 .2] .* [imPos(1), pos(4), pos(3:4)];
set(barAxes, 'Position', axPos)
% Create the default patch/line used to mark the level.
xpatch = [0 0 0 0];
ypatch = [0 0 1 1];
hPatch = patch(xpatch, ypatch, 'r', 'EdgeColor', 'r', 'EraseMode', 'none');
xline = [100 0 0 100 100];
yline = [0 0 1 1 0];
hLine = line(xline, yline, 'EraseMode', 'none');
set(hLine, 'Color', get(gca, 'XColor'));