Table of Contents

Creating images of brain views

Motivation

One of the reasons why you may want to use NeuroElf is for visualization. And while the online browsing capability is certainly helpful in identifying good visualizations, it can then be very tedious to create an entire series of them (e.g. for different subjects, etc.) by using the GUI directly. Hence I tried to make most of the steps you can perform via the mouse or keyboard scriptable.

Overview

Importantly, once the GUI is loaded, pretty much all functions are available by performing a call of the form:

neuroelf_gui('sub_function', 'argument1', [2, 3, 4], {'a', 'b'});

And as a more practical example, let's introduce the screenshot function:

neuroelf_gui('help', 'screenshot')

which returns the help text associated with this function:

ne_screenshot  - create a screenshot file

FORMAT:       ne_screenshot(SRC, EVT, [, object [, filename [, hq]]])

Input fields:

      SRC, EVT    Matlab handle callback inputs (discarded)
      object      can be empty, 0 (main fig), or figure/axes handle
      filename    optional filename (otherwise requested)
      hq          high-quality flag (set to 'high-q' for oversampling)

No output fields.

Example:

   neuroelf_gui('screenshot', 'BS123456', 'screenshot_1234.png', 'high-q');

   creates the file 'screenshot_1234.png' with high-quality oversampling
   from satellite window with ID 'BS123456'

Components

Importantly, an “undocked” window is assigned an 8-character long token, which can then be used to address this window from the command line. To script an entire (and useful) function, I would assume the following steps must be performed (with some of them being optional):

Loading files

I'll write up another page about this, but briefly put, to see if a file is loaded, the easiest way I can think of would be a try/catch construction:

% store filename in a variable,
% which can be constructed from arguments to a function!
objectfilename = '/Users/Jochen/Documents/interesting_stats.vmp';
objectfiletype = 'vmp';
 
% access to the loaded objects via the xff constructor
x = xff;
 
% then attempt to access this file
try
    object = x.Document(objectfilename);
catch
    try
        object = xff(objectfilename);
        if ~isxff(object, objectfiletype)
            error('INVALID_XFF_FILE');
        end
    catch
        error('script:error', 'File %s not readable.', objectfilename);
    end
end

And once the object is available, it can easily be added to the GUI (and made the current object) using

object.Browse;

Configuring a view

There are several options, but in general, you would probably want to achieve at the very least the objectives of loading up all the surfaces you need, match the corresponding surface maps (to each of them, if you want to display multiple surfaces), and finally select the surface(s) you want to display together with a preferred view (angle, etc.).

Selecting maps

The call that makes an object current also allows to specify which map (or volume) is to be shown in the viewer:

vmp.Browse(map_number);

In addition, the selection (click into the maps list) issues a call that can be scripted as well:

neuroelf_gui('setcstatmap', map_number); % for VMPs or
surface_object.Browse; % make surface_object the current object
neuroelf_gui('setcsrfstatmap', map_number); % select SMPs -- requires matching number of vertices

Selecting multiple surfaces

To generate a scenery, multiple surfaces (or DTI fiber tracts) can be combined in a view. The function call for this is

neuroelf_gui('sceneryselect', {surface_object1, surface_object2}); % for the main viewer window or
neuroelf_gui('sceneryselect', {surface_object1, surface_object2}, 'BS123456'); % for the satellite with ID BS123456

Altering surface properties by script

Sometimes it is also important to be able to change surface properties (e.g. transparency or surface-specific translation values). For this, you can use

neuroelf_gui('setsceneprops', surface_object1, {[0, 0, 0], [0 0 0], [1], [.5], 'f'});

Whereas the elements in the cell array are (in order):

If the surface is displayed in an external window, it is important to re-select the scenery afterwards (as the surface object itself does only carry a reference to the MATLAB patch UI object in the main viewer):

neuroelf_gui('setsceneprops', surface_object1, {[0, 0, 0], [0 0 0], [1], [.5], 'f'});
neuroelf_gui('sceneryselect', {surface_object1, surface_object2}, 'BS123456');

Undocking the main viewer configuration into a satellite

While the main viewer has several advantages when it comes to manipulating objects (e.g. smoothing surfaces, etc.), the biggest shortcoming is the fact that the axes object in MATLAB isn't the only visible portion of the figure, which makes it difficult to take a screenshot of the surface viewer alone.

For this purpose, the current view (slicing, surface, or rendering) can be “undocked” into a separate window using

[hSat, tags, iSat] = neuroelf_gui('undock');

The iSat variable then contains the 8-character token (window ID) that can be used to further address this window

Resizing the undocked view

And the first thing that may be of interest is to resize this undocked view

neuroelf_gui('satresize', iSat, [width, height]);

Changing the background color (surfaces only for now)

Another thing you may want to do is setting the background color:

neuroelf_gui('satsetcolor', iSat, [red, green, blue]);

whereas each of red, green, and blue are 0-255 coded RGB values (so use [255, 255, 255] for white).

Manipulating the viewpoint

Naturally, it is important to be able to control what is being shown (from what angle and overall zoom, etc.). For this, use the function “setsurfpos”:

neuroelf_gui('setsurfpos', iSat, {azi, zen, trans, zoom, timeindex});

The angles (azi and zen) are given in degrees (not radians), the translation must be 1×3 double, although the first element will be discarded (no translation in X direction, where X is left/right along the brain axis). The zoom must be within .2 and 5, and the timeindex can be used for morph effects and color changes (e.g. for a surface-space sampled whole-brain time course average).

Taking a screenshot

Finally, to take a screenshot (save an image of the surface to disk), use

neuroelf_gui('screenshot', iSat, image_filename, 'high-q');

Whereas the image_filename can of course be a sprintf(…) expression within a loop. The “high-q” flag instructs the function to use oversampling (which really is only useful for surface windows, though).

Putting it all together

So, an entire script could look like this:

% files to load/display
lh_srf = '/Users/Jochen/Documents/demo/lh.srf';
rh_srf = '/Users/Jochen/Documents/demo/rh.srf';
 
% VMP (will be sampled on surfaces)
stast_vmp = '/Users/Jochen/Documents/demo/stats.vmp';
 
% load objects (without loading again)
x = xff;
try
    lh = x.Document(lh_srf);
catch
    lh = xff(lh_srf);
end
try
    rh = x.Document(rh_srf);
catch
    rh = xff(rh_srf);
end
try
    vmp = x.Document(stats_vmp);
catch
    vmp = xff(stats_vmp);
end
 
% adding all to viewer
vmp.Browse;
lh.Browse;
rh.Browse;
 
% set in scenery
neuroelf_gui('sceneryselect', {lh, rh});
 
% then sample the stats
[lhsmp, rhsmp] = neuroelf_gui('vmp_createsmp');
 
% undock the window
[hSat, tags, iSat] = neuroelf_gui('undock');
 
% resize satellite
neuroelf_gui('satresize', iSat, [1080, 720]);
 
% set color (to white)
neuroelf_gui('satsetcolor', iSat, [255, 255, 255]);
 
% loop over a rotation (create movie frames)
mfc = 1;
for fc = [90:360, 1:90]
 
    % set position
    neuroelf_gui('setsurfpos', iSat, {fc, 15, [0, 0, 0], 1, 0});
 
    % screenshot
    neuroelf_gui('screenshot', iSat, sprintf('movieframe%03d.png', mfc), 'high-q');
 
    % increase counter
    mfc = mfc + 1;
end
 
% delete satellite
neuroelf_gui('closesatwindow', iSat);
 
% unload created objects
rhsmp.ClearObject;
lhsmp.ClearObject;