Memory-mapped data-sharing for real-time processing

To enhance the real-time processing capabilities of Scanbox we now provide a general mechanism to share frames being collected with another application running concurrently on the same computer via a memory mapped file.

This general and flexible mechanism allows any user to extend the real-time processing of Scanbox beyond what is already offered.

As an example, this interface allows one to perform pixel-by-pixel image processing in ways that do not require prior definitions of ROIs. One such case would be the calculation of temporally encoded cortical maps by on-the-fly calculations of the magnitude/phase of each pixel.

All you have to do to enable this feature is to set the “mmap” variable to 1 in the configuration file and, in those imaging sessions you want to stream the data, enable the “Memory map” checkbox in the real-time processing panel:

realtime

The memory mapped file contains a 16 word header (int16s) that allows communication between Scanbox and another process, which is then followed by the imagery data.  Only the first 4 words of the header are used at the moment (the other are reserved for future use).

The first word is used as a semaphore between the applications to control access to the memory mapped file.  The value of this variable is -1 if the file can be used by Scanbox to stream data, it is -2 if Scanbox has stopped imaging, and it is a non-negative number that corresponds to a frame if Scanbox has copied the data to the memory mapped file.

The second and third variables represent the size of the frame, used by the application processing the data to interpret the organization of the file as an image.

The fourth variable is a copy of the TTL1, which is high during a stimulus presentation and low otherwise.

As an example of a Matlab process that consumes data from Scanbox and all it does is compute the average frame is listed below.


% Simple example of memory mapped processing in Scanbox

% Open memory mapped file -- just header first
mmfile = memmapfile('scanbox.mmap','Writable',true, ... 
 'Format', { 'int16' [1 16] 'header' } , 'Repeat', 1);
flag = 1;

% Process all incoming frames until Scanbox stops

while(true)

   while(mmfile.Data.header(1)<0) % wait for a new frame...
     if(mmfile.Data.header(1) == -2) % exit if Scanbox stopped
     return;
     end
   end
 
 display(sprintf('Frame %06d',mmfile.Data.header(1))) % print frame# being processed
 
 if(flag) % first time? Format chA according to lines/columns in data
   mmfile.Format = {'int16' [1 16] 'header' ; ... 
   'uint16' double([mmfile.Data.header(2) mmfile.Data.header(3)]) 'chA'};
   mchA = double(mmfile.Data.chA);
   flag = 0;
 end
 
 mchA = mchA + double(mmfile.Data.chA);
 
 % Here you can do whatever you want with
 % your data.... I am just accumulating.
 
 mmfile.Data.header(1) = -1; % signal Scanbox that frame has been consumed!
end

clear(mmfile)

imagesc(mchA); % display mean image
truesize

The interface allows you to use any language that provides you access to memory mapped files, such as Python.

So, if you happen to write some neat real-time image processing module for Scanbox, feel free to share!

A set of more readable functions that encapsulate the basic functionality shown above will be provided soon to make the writing of real-time processing applications easier, and we may also adopt a double-buffering or ring-buffer mechanisms.