====== 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):
* the files that are to be visualized need to be loaded (or, even better, checked to see if they are loaded already)
* the files must be "selected" (made the current objects) for NeuroElf's GUI functions to work properly
* a "scene" must be configured (e.g. which stats maps at what threshold, colors, etc.)
* at this point, the initial "view" must be set (e.g. for surfaces or rendering views the two angles, zoom factor, etc.)
* the view is then undocked
* a screenshot is produced
* if a movie is to be made, the view can be altered in a loop with taking multiple screenshots
===== 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):
* surface-specific translation
* surface-specific rotation
* surface-specific scaling (scalar)
* alpha (transparency) value
* faces ('f') or wireframe ('w') mode
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 1x3 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;