Acquisition Data Structures

Two classes carry acquired data through ScanImage®. scanimage.interfaces.StripeData is what the imaging system hands to the rest of the application every time a stripe of samples is ready; scanimage.mroi.RoiData is the per-ROI image container that a StripeData carries. Between them they are what almost every piece of user analysis code touches, so it is worth knowing their exact shapes.

See also

hSI.hDataManager produces them, hSI.hDisplay exposes them, and Acquisition Metadata describes how their fields end up in the Tiff header.


RoiData

scanimage.mroi.RoiData holds the image data for one ROI at multiple z depths. It is a handle class, and it is copyable (matlab.mixin.Copyable).

hRoiData = hSI.hDisplay.getRoiDataArray();   % 1 x nRois array

Image data

Property

Description

imageData

Cell of cell arrays, indexed imageData{channelIdx}{zIdx}. The first index runs over channels, the second over zs. The image data is transposed.

channels

Numeric array of channel numbers, giving the meaning of the first index.

zs

Numeric array of z values, giving the meaning of the second index.

transposed

Logical, default true. Whether the image data is stored transposed.

hRoi

Handle to the scanimage.mroi.Roi this data belongs to. Use hRoi.get(z) to get the scanfield at a particular z.

Important

The double indexing is channel-first, z-second, and the arrays are transposed relative to how the image is displayed. A frame for channel 1 at the first z is hRoiData(k).imageData{1}{1}.'.

hRoiDatas = hSI.hDisplay.getRoiDataArray();

for idx = 1:numel(hRoiDatas)
    hRd = hRoiDatas(idx);
    fprintf('%s: %d channels x %d zs\n',hRd.hRoi.name,numel(hRd.channels),numel(hRd.zs));

    chIdx = find(hRd.channels == 1);    % locate channel 1
    zIdx  = 1;
    img = hRd.imageData{chIdx}{zIdx}.';  % transpose for display orientation
    imagesc(img);
end

Striping

When hSI.hScan2D.stripingEnable is set, a RoiData may hold a partial frame.

Property

Description

stripePosition

Cell array of [startLine endLine], one per z. Empty means the data is a full frame.

stripeFullFrameNumLines

Number of lines in the complete frame, per z. Together with stripePosition this tells you where the stripe sits in the frame.

Warning

Code that assumes a full frame will silently process partial data when striping is on. Either check stripePosition is empty, or hook frameAcquired rather than the RoiDataUpdated event.

Timing and provenance

Property

Description

acqNumber

Acquisition number.

frameNumberAcq

Frame number within the current acquisition.

frameNumberAcqMode

Frame number within the current acquisition mode.

frameTimestamp

Timestamp of the last stripe acquired, in the current acquisition mode.

frameTimestampByZIdx

Timestamps per z index.

motionOffset

2 x n array of x, y offsets for all zs, in pixel coordinates.

absStagePosition

3 x 1 stage position in absolute coordinates, microns. Recorded when a ROI is added as a motion detection or correction reference.

acqParamBuffer

Buffer of frequently used parameters, so they are not recomputed per frame.

All of these are copied from the StripeData the RoiData arrived in.

Methods

Method

Description

hRd.merge(hRoiData)

Merge another RoiData into this one. Handles striped images by indexing into the frame.

hRd.mergeIn(newRoiData)

Merge in place.

hRd.averageRoiData(newRoiData,alpha)

Exponentially average new data into this one with coefficient alpha. This is what backs frame averaging.

[im,zs] = hRd.maxProjZFromData()

Maximum intensity projection over z. Assumes the same scanfield at every z.

hRd.castImageData(newType)

Cast the image data to another numeric type.

hRd.multiplyData(factor)

Scale the image data.

hRd.onlyKeepChannels(chs) / deleteChannels(chs)

Subset by channel.

hRd.onlyKeepZs(zs) / deleteZs(zs)

Subset by z.

hRd.resetData(), resetDataToZero(), resetDataToEmpty()

Clear the buffers, leaving the structure, zeroed, or empty respectively.

RoiData implements saveobj / loadobj, so it can be saved to a .mat file and read back with its ROI geometry intact.

The imageDataUpdated event fires when imageData changes; its event data names which zs were updated.

Note

scanimage.mroi.RoiDataSimple is a lightweight variant used by the Tiff reading utilities - see Generate Multi-ROI Data From Tiff. It carries the image data and ROI geometry without the live-acquisition machinery.


StripeData

scanimage.interfaces.StripeData is the unit of data flow during an acquisition. One is produced per stripe; with striping disabled that means one per frame. It is passed to hSI.hDataManager.stripeAcquired(stripeData) and is available to user functions hooked on frameAcquired.

Payload

Property

Description

roiData

1D cell array of scanimage.mroi.RoiData. Note this is a cell array, whereas hSI.hDisplay.getRoiDataArray() returns an object array.

rawData

Raw data samples.

rawDataStripePosition

Start position of the raw samples.

channelNumbers

Active channel numbers for the current acquisition.

transposed

Whether the image data is transposed.

histogramChannels

Channels for which histogram data was computed.

Position in the acquisition

Property

Description

frameNumberAcqMode

Frame number counted from the start of the acquisition mode.

frameNumberAcq

Frame number within the current acquisition.

acqNumber

Current acquisition number.

stripeNumber

Stripe number within the frame.

stripesRemaining

Unprocessed stripes still in the queue. A useful backpressure signal: if this grows, your callback is too slow.

totalAcquiredFrames

Total frames acquired.

zIdx, zSeries

Index into, and the full list of, the z series for the current acquisition.

stackMode

Which stack mode the acquisition is using.

Boundary flags

These are what user-function code branches on.

Flag

True when

startOfFrame

This is the first stripe of a frame.

endOfFrame

This is the last stripe of a frame.

startOfVolume / endOfVolume

This stripe begins or ends a volume.

endOfAcquisition

endOfFrame and this is the last frame of the acquisition.

endOfAcquisitionMode

endOfFrame and this is the end of the acquisition mode.

overvoltage

An overvoltage was detected on any active channel during the acquisition mode.

Timing

Property

Description

epochAcqMode

Time of the first pixel of the acquisition mode, as a date string.

frameTimestamp

Seconds from epochAcqMode to the first pixel of this frame.

acqStartTriggerTimestamp

Seconds to the acquisition start trigger of the current acquisition.

nextFileMarkerTimestamp

Seconds to the last next-file marker. NaN if none was recorded.

Spatial context

Property

Description

focalPoint

scanimage.mroi.coordinates.Points object giving the focal point in absolute coordinates. Added by ScanImage as the stripe is dispatched - so a frame knows where the microscope was looking when it was taken.

motionMatrix

4 x 4 matrix estimating 3D motion.

% where in the sample was this frame acquired?
hPt = stripeData.focalPoint.transform(hSI.hCoordinateSystems.hCSSampleRelative);
fprintf('frame %d at %.1f %.1f %.1f um\n',stripeData.frameNumberAcqMode,hPt.points);

Methods

Method

Description

str = sd.getFrameDescription(useJson)

Build the per-frame metadata string that is written into the Tiff ImageDescription tag. Only valid at endOfFrame. See Acquisition Metadata.

sd.merge(hStripeData)

Merge another stripe’s ROI data into this one.

sd.mergeIn(newStripeData)

Merge in place, taking the new stripe’s position fields.

sd.castRoiData(newType) / multiplyRoiData(factor)

Apply the corresponding RoiData operation to every ROI.


Using them from a user function

The frameAcquired event is the normal entry point. Guard on the boundary flags rather than assuming one call per frame.

function myFrameCallback(src,evt,varargin)
    hSI = src.hSI;
    sd  = hSI.hDataManager.lastStripeData;

    if isempty(sd) || ~sd.endOfFrame
        return    % partial stripe; wait for the full frame
    end

    for idx = 1:numel(sd.roiData)
        hRd = sd.roiData{idx};
        chIdx = find(hRd.channels == 1);
        if isempty(chIdx); continue; end

        img = hRd.imageData{chIdx}{1}.';
        fprintf('frame %d, roi %s, mean %.1f\n', ...
            sd.frameNumberAcqMode, hRd.hRoi.name, mean(img(:)));
    end
end

Warning

This callback runs on the acquisition path. Work done here delays the display and, under load, causes dropped frames. Watch stripesRemaining; if it climbs, buffer the data and process it on a timer instead.

See also

Recipes for complete worked examples.