Code covered by the BSD License  

Highlights from
IMAQCALC - Image acquisition calculator

image thumbnail
from IMAQCALC - Image acquisition calculator by David Tarkowski
An image acquisition calculator to calculate the expected acquisition rate.

imaqcalc
function imaqcalc
%IMAQCALC Create an image acquisition calculator.
% 
%    IMAQCALC creates an interface for calculating the approximate image 
%    acqusition rate you can expect based on the image and acquisition 
%    parameters you desire. 
%
%    In most cases, how fast you can acquire image data is dependent on
%    various parameters. In certain cases, the acquisition rate will be
%    limited by the bandwidth of the bus being used. In other cases, how
%    fast you can stream image data to memory will be limited by the
%    hardware's pixel clock, the image resolution and bit depth, and the 
%    amount of memory available on your system.
%
%    The interface created consists of different panels that help you 
%    calculate the different parameters associated with acquiring image 
%    data. These panels are:
%    
%       Hardware Parameters - allows you to select the bus type you wish 
%                             to use for the acquisition, as well as the 
%                             maximum pixel clock supported by the hardware.
%       Image Parameters    - defines the charactersitics of the image data
%                             you wish to acquire.
%       Frames To Buffer    - used to determine the number of image frames
%                             you can acquire into memory.
%       Target Data Rate    - allows you to specify the desired data rate
%                             you wish to achieve during the acquisition.
%       Target Pixel Clock  - allows you to specify the desired pixel clock
%                             for the acquisition.
%       Target Frame Rate   - allows you to specify the desired acquisition
%                             frame rate you want to achieve.
%
%    There are 3 types of messages IMAQCALC will display for each panel:
%
%       "...OK"                 - the desired acquisition setting can be 
%                                 met with the given hardware, image, and 
%                                 acquisition parameters.
%       "...too high"           - the desired acquisition settings are too 
%                                 high given the hardware, image, and 
%                                 acquisition parameters specified. This 
%                                 requires some adjustments be made to the 
%                                 image or acquisition settings.
%       "...bandwidth exceeded" - the desired acquisition settings may 
%                                 exceed the bandwidth limitations of the 
%                                 bus. If the hardware uses compression or
%                                 on-board memory to manage the data
%                                 transfer, the specified acquisition
%                                 settings may be sustainable.
%
%    Note, all calculations are based on transferring raw, uncompressed 
%    image data. 
%
%    Memory availability is determined using the IMAQMEM function provided 
%    by the Image Acquisition Toolbox. If the Image Acquisition Toolbox is
%    not available, the Frames To Buffer panel will not be updated.
%
%    See also IMAQMEM, TIMER. 

%    CP 4-13-04
%    Copyright 2004 The MathWorks, Inc. 

% Search for an existing figure.
[fig, figName] = localFindFigure;
if ~isempty(fig)
    figure(fig);
    return;
end

% Constants.
% 1 MB = 1,048,576 bytes
% Bus rates => MB = (MHz*bits) * 1 byte/8 bits
constants.bytesPerMb = 1048576;
constants.maxMbPerSecond = {...
    'Ethernet (T10)', 1.25, ...
    'USB 1.x', 1.5, ...
    'Ethernet (T100)', 12.5, ...
    'FireWire (IEEE-1394)', 50, ...
    'USB 2.0', 60, ...
    'Gigabit Ethernet', 125, ...
    'PCI (33MHz / 32bit)', 132, ...
    'PCI (66MHz / 32bit)', 264, ...
    'PCI (66MHz / 64bit)', 528, ...
    'PCI-X (133MHz / 64bit)', 1064, ...
    };

% Need to create the base figure.
figProps.CreateFcn = {@movegui, 'center'};
figProps.DeleteFcn = @localTimerMngr;
figProps.MenuBar = 'none';
figProps.Name = figName;
figProps.NumberTitle = 'off';
figProps.Tag = strrep(figName, ' ', '');
figProps.Units = 'normalized';
figProps.Userdata = constants;
fig = figure(figProps);
figColor = get(fig, 'Color');

% Create the different panels.
xEdgeOffset = 0.01;
yEdgeOffset = 0.01;
localCreateHWParamsPanel(xEdgeOffset, yEdgeOffset);
localCreateIMParamsPanel(xEdgeOffset, yEdgeOffset);
localCreateBufferPanel(xEdgeOffset, yEdgeOffset);
localCreateDataRatePanel(xEdgeOffset, yEdgeOffset);
localCreatePxlClockPanel(xEdgeOffset, yEdgeOffset);
localCreateFPSPanel(xEdgeOffset, yEdgeOffset);

% Configure generic settings for UI panels and controls.
uips = findobj(fig, 'Type', 'uipanel');
uitext = findobj(fig, 'Type', 'uicontrol', 'Style', 'text');
uiedits = findobj(fig, 'Type', 'uicontrol', 'Style', 'edit');
set([uips;uitext], 'BackgroundColor', figColor)
set(uiedits, 'BackgroundColor', 'white')
set(uips, 'TitlePosition', 'centertop'); 

% Initialize values and hide the figure once 
% all the UI controls have been added.
localInitUI(fig);
set(fig, 'HandleVisibility', 'off');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI CALLBACKS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localInitUI(fig)

handles = guihandles(fig);

% Configure the callbacks for all the uicontrols 
% the user might change.
set(handles.BusType, 'Callback', @localIMParamsCallback)
set(handles.MaxBoardClock, 'Callback', @localIMParamsCallback)
set(handles.Width, 'Callback', @localIMParamsCallback)
set(handles.Height, 'Callback', @localIMParamsCallback)
set(handles.BitsPerPixel, 'Callback', @localIMParamsCallback)
set(handles.FPSFramesPerSecond, 'Callback', @localFPSCallback)
set(handles.DataRateMbPerSecond, 'Callback', @localDataRateCallback)
set(handles.PixelClock, 'Callback', @localPixelClockCallback)
set(handles.FramesToBuffer, 'Callback', @localBufferCallback)

% Once the callbacks are set up, initialize all 
% controls to their default values.
set(handles.MaxBoardClock, 'String', '25')
set(handles.Width, 'String', '640')
set(handles.Height, 'String', '480')
set(handles.BitsPerPixel, 'String', '24')
set(handles.FPSFramesPerSecond, 'String', '30')
set(handles.DataRateMbPerSecond, 'String', '50')
set(handles.PixelClock, 'String', '25')
set(handles.FramesToBuffer, 'String', '10')

% Configure the timer object so we 
% can update the Buffer panel.
localTimerMngr(fig);

% Trigger all the callbacks to calculate
% the different values for the panels based 
% on the defaults we just configured.
localIMParamsCallback(fig, []);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localTimerMngr(obj, event)
% Create or clean up the timer object used to
% update the Buffer panel.

if nargin==2,
    % Need to clean up the timer.
    t = timerfind('Tag', get(obj, 'Name'));
    if ~isempty(t)
        stop(t);
        delete(t);
    end
else
    handles = guihandles(obj);
    if exist('imaqmem')==2
        % Create a timer to update the memory status.
        t = timer('Tag', get(obj, 'Name'), 'ExecutionMode', 'fixedSpacing', ...
            'TimerFcn', {@localTimerCallback, handles.MemoryAvailable, ...
            handles.MaxFrames, handles.MbPerFrame});
        start(t)
    else
        warning('MATLAB:imaqcalc:noimaq', ...
            'The Image Acquisition Toolbox IMAQMEM function is unavailable.\nThe Frames To Buffer panel will not be updated.');
        set(handles.FramesToBuffer, 'String', '0', 'Enable', 'off')
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localTimerCallback(obj, event, memField, maxFramesField, mbFrameField)
% Executed by the timer object to update the buffer 
% panel with the current memory information.

if isvalid(obj),
    mbMemory = imaqmem('AvailPhys')/1000000;
    set(memField, 'String', mbMemory);
    mbFrame = str2num(get(mbFrameField, 'String'));
    set(maxFramesField, 'String', floor(mbMemory/mbFrame));
    localBufferCallback(memField, event);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localIMParamsCallback(obj, event)
% Callback for the ImageParameters panel.

handles = guihandles(obj);
height = str2num(get(handles.Height, 'String'));
width = str2num(get(handles.Width, 'String'));
bitsPerPixel = str2num(get(handles.BitsPerPixel, 'String'));

% Update the panel values.
set(handles.PixelsPerFrame, 'String', height*width)
set(handles.BitsPerFrame, 'String', height*width*bitsPerPixel)
set(handles.BytesPerFrame, 'String', height*width*bitsPerPixel/8)
set(handles.MbPerFrame, 'String', height*width*bitsPerPixel/8/1048576)

% Notify all other callbacks.
localFPSCallback(obj, event);
localDataRateCallback(obj, event);
localPixelClockCallback(obj, event);
localBufferCallback(obj, event);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localBufferCallback(obj, event)
% Callback for the Buffer panel.

handles = guihandles(obj);
toBuffer = str2num(get(handles.FramesToBuffer, 'String'));

% Check limits.
maxFrames = str2num(get(handles.MaxFrames, 'String'));
failed = toBuffer>maxFrames;
localUpdateMsg(0, handles.FramesToBufferMsg, ...
    failed, 'The number of frames to buffer ');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localDataRateCallback(obj, event)
% Callback for the DataRate panel.

handles = guihandles(obj);
mbs = str2num(get(handles.DataRateMbPerSecond, 'String'));
mbFrame = str2num(get(handles.MbPerFrame, 'String'));

% Update the panel values.
desFPS = mbs/mbFrame;
set(handles.DataRateFramesPerSecond, 'String', desFPS)

% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
failed = desFPS*pixelsPerFrame/1000000>maxClock;

localUpdateMsg(mbs, handles.DataRateMsg, failed, 'Your data rate ');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localPixelClockCallback(obj, event)
% Callback for the PixelClock panel.

handles = guihandles(obj);
pixelClock = str2num(get(handles.PixelClock, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
bytesPerFrame = str2num(get(handles.BytesPerFrame, 'String'));

% Update the panel values.
set(handles.SecondsPerFrame, 'String', pixelsPerFrame/(pixelClock*1000000))

secFrame = str2num(get(handles.SecondsPerFrame, 'String'));
fps = 1/secFrame;
set(handles.PixelClockFramesPerSecond, 'String', fps)
set(handles.PixelClockMbPerSecond, 'String', fps*bytesPerFrame/1000000)

% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
failed = pixelClock>maxClock;

mbs = str2num(get(handles.PixelClockMbPerSecond, 'String'));
localUpdateMsg(mbs, handles.PixelClockMsg, failed, 'Your pixel clock ');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localFPSCallback(obj, event)
% Callback for the FramesPerSecond panel.

handles = guihandles(obj);
fps = str2num(get(handles.FPSFramesPerSecond, 'String'));
pixelsPerFrame = str2num(get(handles.PixelsPerFrame, 'String'));
bytesPerFrame = str2num(get(handles.BytesPerFrame, 'String'));

% Update the panel values.
equivClock = fps*pixelsPerFrame/1000000;
set(handles.EquivalentPixelClock, 'String', equivClock)
set(handles.FPSMbPerSecond, 'String', fps*bytesPerFrame/1000000)

% Check limits.
maxClock = str2num(get(handles.MaxBoardClock, 'String'));
failed = equivClock>maxClock;

mbs = str2num(get(handles.FPSMbPerSecond, 'String'));
localUpdateMsg(mbs, handles.FPSMsg, failed, 'Your frame rate ');

%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI PANELS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateHWParamsPanel(xEdgeOffset, yEdgeOffset)
% Create the HardwareParameters panel and controls.

pnlPos = [0+xEdgeOffset 0.88+yEdgeOffset 1-(2*xEdgeOffset) 0.12-(2*yEdgeOffset)];
uipanel('Title', 'HARDWARE PARAMETERS', 'Position', pnlPos);

% Create a hidden panel so the edit fields are 
% created with respect to it.
pnlPos = [0+xEdgeOffset 0.90+yEdgeOffset 0.5-(2*xEdgeOffset) 0.10-(2*yEdgeOffset)];
pnl = uipanel('Position', pnlPos, 'Visible', 'off');
localAddTextList(pnl, {'Bus Type:'});

constants = get(get(pnl, 'Parent'), 'Userdata');
uic = uicontrol('Style', 'popupmenu', 'Tag', 'BusType', ...
    'String', constants.maxMbPerSecond(1:2:end), ...
    'Units', 'normalized', 'BackGroundColor', 'white',...
    'FontWeight', 'bold', 'Parent', pnl, 'Value', 7, ...
    'Position', [1/3, 0.05, 2/3, 1/2]);

% Create a hidden panel so the edit fields are 
% created with respect to it.
pnlPos = [0.5+xEdgeOffset 0.90+yEdgeOffset 0.5-(2*xEdgeOffset) 0.10-(2*yEdgeOffset)];
pnl = uipanel('Position', pnlPos, 'Visible', 'off');
localAddTextList(pnl, {'Maximum Pixel Clock (MHz):'});
localAddEditFieldList(pnl, {'MaxBoardClock', true});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateIMParamsPanel(xEdgeOffset, yEdgeOffset)
% Create the ImageParameters panel and controls.

pnlPos = [0+xEdgeOffset 0.22+yEdgeOffset 0.5-(2*xEdgeOffset) 0.66-(2*yEdgeOffset)];
pnl = uipanel('Title', 'IMAGE PARAMETERS', 'Position', pnlPos);

localAddTextList(pnl, ...
    {'Width (pixels):', 'Height (lines):', 'Bits / Pixel:', ...
    'Pixels / Frame:', 'Bits / Frame:', 'Bytes / Frame:', 'MB / Frame:'});

localAddEditFieldList(pnl, ...
    {'Width', true, 'Height', true, 'BitsPerPixel', true, ...
    'PixelsPerFrame', false, 'BitsPerFrame', false, ...
    'BytesPerFrame', false, 'MbPerFrame', false});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateBufferPanel(xEdgeOffset, yEdgeOffset)
% Create the Buffer panel and controls.

pnlPos = [0+xEdgeOffset 0+yEdgeOffset 0.5-(2*xEdgeOffset) 0.29-yEdgeOffset];
pnl = uipanel('Title', 'FRAMES TO BUFFER', 'Position', pnlPos);

localAddTextList(pnl, ...
    {'Number of Frames to Buffer:', 'Memory Available (MB):', 'Maximum Number of Frames:'});

fieldSpacing = localAddEditFieldList(pnl, ...
    {'FramesToBuffer', true, 'MemoryAvailable', false, 'MaxFrames', false});

uicontrol('Style', 'text', 'Units', 'normalized', ...
    'String', 'The number of frames to buffer is OK.', ...
    'Parent', pnl, 'Tag', 'FramesToBufferMsg', ...
    'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateDataRatePanel(xEdgeOffset, yEdgeOffset)
% Create the DataRate panel and controls.

pnlPos = [0.5+xEdgeOffset 0.63+yEdgeOffset 0.5-(2*xEdgeOffset) 0.25-(2*yEdgeOffset)];
pnl = uipanel('Title', 'TARGET DATA RATE', 'Position', pnlPos);

localAddTextList(pnl, {'MB / Second:', 'Frames / Second:'});

fieldSpacing = localAddEditFieldList(pnl, ...
    {'DataRateMbPerSecond', true, 'DataRateFramesPerSecond', false});

uicontrol('Style', 'text', 'String', 'Your data rate is OK.', ...
    'Units', 'normalized', 'Parent', pnl, 'Tag', 'DataRateMsg', ...
    'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreatePxlClockPanel(xEdgeOffset, yEdgeOffset)
% Create the PixelClock panel and controls.

pnlPos = [0.5+xEdgeOffset 0.29+yEdgeOffset 0.5-(2*xEdgeOffset) 0.34-yEdgeOffset];
pnl = uipanel('Title', 'TARGET PIXEL CLOCK', 'Position', pnlPos);

localAddTextList(pnl, {'Pixel Clock (MHz):', 'Seconds / Frame:', ...
    'Frames / Second:', 'MB / Second:'});

fieldSpacing = localAddEditFieldList(pnl, ...
    {'PixelClock', true, 'SecondsPerFrame', false, ...
    'PixelClockFramesPerSecond', false, 'PixelClockMbPerSecond', false});

uicontrol('Style', 'text', 'String', 'Your pixel clock is OK.', ...
    'Units', 'normalized', 'Tag', 'PixelClockMsg', 'Parent', pnl, ...
    'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localCreateFPSPanel(xEdgeOffset, yEdgeOffset)
% Create the FramesPerSecond panel and controls.

pnlPos = [0.5+xEdgeOffset 0+yEdgeOffset 0.5-(2*xEdgeOffset) 0.29-yEdgeOffset];
pnl = uipanel('Title', 'TARGET FRAME RATE', 'Position', pnlPos);

localAddTextList(pnl, ...
    {'Frames / Second:', 'Equivalent Pixel Clock (MHz):', 'MB / Second:'});

fieldSpacing = localAddEditFieldList(pnl, {'FPSFramesPerSecond', true, ...
    'EquivalentPixelClock', false, 'FPSMbPerSecond', false});

uicontrol('Style', 'text', 'String', 'Your frame rate is OK.', ...
    'Units', 'normalized', 'Tag', 'FPSMsg', 'Parent', pnl, ...
    'Position', [0.05, 0.075*fieldSpacing, 1-0.1, fieldSpacing/2]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIGURE UI HELPERS:
%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localAddTextList(pnl, names)
% Add the list of text fields passed in as
% an evenly spaced, vertical list of text uicontrols.

xFieldOffset = 0.05;
yEdgeOffset = 0.015;

% If only one name needs to be added, 
% allow it to take up extra room.
nNames = length(names);
if nNames>1
    fieldSpacing = 1/(nNames+1);
else
    fieldSpacing = 1/nNames;
end

% Iterate through each text string we need to add.
for orderNum=1:nNames
    xOffset = xFieldOffset;
    yOffset = 1 - (orderNum*fieldSpacing);
    width = 2/3;
    height = fieldSpacing/2.5;
    uic = uicontrol('Style', 'text', 'String', names{orderNum}, ...
        'Units', 'normalized', 'Parent', pnl, 'HorizontalAlignment', 'left', ...
        'Position', [xOffset, yOffset, width, height]);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function fieldSpacing = localAddEditFieldList(pnl, entries)
% Add the list of edit controls as an evenly spaced, 
% vertical list of edit uicontrols.
% Each control has a Tag name and a corresponding logical
% indicating if the edit uicontrol should be enabled or not.

xFieldOffset = 0.05;
yEdgeOffset = 0.015;

% If only one name needs to be added, 
% allow it to take up extra room.
nNames = length(entries)/2;
if nNames>1
    fieldSpacing = 1/(nNames+1);
else
    fieldSpacing = 1/nNames;
end

% Iterate through each edit control we need to add.
for orderNum=1:nNames
    xOffset = 2/3;
    yOffset = 1 - (orderNum*fieldSpacing);
    width = 1/3 - xFieldOffset;
    height = fieldSpacing/2;
    
    name = entries{2*orderNum-1};
    editable = entries{2*orderNum};
    if editable
        uic = uicontrol('Style', 'edit', 'Tag', name, 'Units', 'normalized', ...
            'Parent', pnl, 'Position', [xOffset, yOffset, width, height], ...
            'String', '0', 'FontWeight', 'bold');
    else
        uic = uicontrol('Style', 'edit', 'Tag', name, 'Units', 'normalized', ...
            'Enable', 'off', 'String', '0', 'FontWeight', 'bold', ...
            'Parent', pnl, 'Position', [xOffset, yOffset, width, height]);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function localUpdateMsg(mbs, msgHandle, failed, msg)
% Determine what message needs to be displayed.

fig = localFindFigure;
handles = guihandles(fig);

% If the current state of our checks is not failed, 
% check the current bus limitations.
if ~failed
    % Check bus limit.
    constants = get(fig, 'Userdata');
    busLimit = constants.maxMbPerSecond{2*get(handles.BusType, 'Value')};
    if mbs>busLimit
        msg = ['Bus bandwidth (', num2str(busLimit), ' MB/s) exceeded.'];
        color = 'black';
    else
        msg = [msg 'is OK.'];
        color = 'blue';
    end
else
    msg = [msg 'is too high.'];
    color = 'red';
end

set(msgHandle, 'String', msg, 'FontWeight', 'bold', 'ForegroundColor', color);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [fig, figName] = localFindFigure
% Locate the top level figure.

figName = 'Image Acquisition Calculator';
fig = findobj(findall(0), 'Type', 'figure', 'Name', figName);
if ~isempty(fig)
    fig = fig(1);
end

Contact us at files@mathworks.com