Matlab Interface
Table of Contents
- Overview
- Getting Started
- Writing Your Own Scripts
- Adding The Vinci Interface to Your Matlab Path
- Starting Vinci from Matlab
- Connecting to a Running Instance of Vinci
- The Vinci Package
- The Documentation
- Optional Arguments
- Filepaths
- Creating a new Project or Loading an Existing One
- Loading Images
- Getting a Handle to an Image in Vinci
- Reading Metadata From an Image
- Loading an Image Volume into Matlab
- Creating New Images and Cloning Images
- Display Objects
- Evaluating Rois
- Advanced Roi Statistics
- Coregistration
- Comments and further Development
see also: Index
Overview
This is a tutorial which describes how to use the Matlab interface provided by Vinci.
The reason why we implemented this interface is to combine the advantages of Matlab and Vinci to make both even more useful than they are on their own.
Vinci is a tool designed to visualize and analyse medical tomographic images. It’s emphasis is on interactive exploration and evaluation. For the purpose of automation, Vinci provides only some level of scriptability through a Python interface, as well as the ability to record and replay macros.
Matlab, on the other hand, is a programming language well suited for scientific programming, prototyping of ideas and automation of repetitive tasks. Writing interactive, user-interface driven applications with Matlab, however, is not an easy task.
The Matlab interface of Vinci allows you to write scripts and applications in Matlab, which use Vinci for the interactive parts of your program while you can write custom algorithms and analysis steps with the help of Matlab’s toolboxes and libraries.
Here is an incomplete list of things, you can do with the Vinci interface for Matlab:
- Remotely control Vinci from Matlab.
- Automate repetitive tasks in Vinci.
- Load images in Vinci and access the image data within Matlab.
- Generate new images in Matlab and visualize them using Vinci.
- Create rois, measures and profiles and evaluate them from within Matlab.
- A combination of all of these possibilities.
Getting Started
If you want to learn more about how to use the Matlab Interface for Vinci, we suggest you start by running some of the example scripts provided with each Vinci release. In principle, this works very similar on all platforms: you open Matlab and change into the examples directory which is part of every recent Vinci release. Traditionally, software is installed (“deployed”) slightly differently depending on the platform you use - so on Mac OS X, Linux and Windows you will typically find Vinci installations in different locations. The only important distinction here is the path to the examples directory.
In order to run the example scripts, you need to make sure that the Matlab
session is using the right directory. Start Matlab, go to the Matlab “Command
Window” and use the cd
command to change to the examples directory.
Everything else should work “out of the box”.
The following platform specific recipes assume that you have installed
Vinci 3.83 or newer (replace “383” if you are using another version).
- MacOS
- if you use the installer script, you can use the default path, otherwise you need to change “VINCI.app” to “VINCI-383.app”:
cd '/Applications/VINCI.app/Contents/external/matlab/'
- Windows
- the default path on the Windows platform is
C:\Program Files\MPIfSF\vinci_383\external\matlab
, so type
cd 'C:\Program Files\MPIfSF\vinci_383\external\matlab\'
- Linux
- the path to the examples directory depends on where you
installed Vinci on your Linux machine and which platform
id you specified. For example, if you chose
/usr/local/
as the installation directory on a 64 bit Linux, you may have to type
cd '/usr/local/vinci_383-linux-x64/external/matlab/'
in the Matlab shell.
Once your Matlab session is located within the right directory, you should be able to see a number of files named test_*.m in the “Current Folder” window in Matlab. To run an example, open one of the files named test_*.m in the Matlab text editor and press F5 or select “Run” from the “Debug” menu.
Writing Your Own Scripts
Writing your own scripts for Vinci does not require a lot of initial work. The only step required is to tell Matlab where to find the Vinci interface package. The path to the package is the same that we used in the previous section to switch to the examples directory. You can use the following snippet of Matlab code as a starting point for your own scripts.
clear all clc addpath('/path/to/vinci/external/matlab'); c = Vinci.Constants(); %% open a vinci instance and open a new project connection = Vinci.Connect(); commands = Vinci.Commands(connection); commands.newProject();
You have to adjust the path used as an argument to the addpath command. Once you have done this, you can run the script. If everything works correctly, a new instance of Vinci with an empty project will appear. Starting from here, you can add additional code to remote control Vinci.
Adding The Vinci Interface to Your Matlab Path
If you plan to write several Matlab scripts for Vinci, you can permanently add the Vinci Matlab package to your Matlab path. Open a new instance of Matlab and type
addpath('/path/to/vinci/external/matlab');
savepath();
Adding the Vinci package to the Matlab path has the advantage, that it is not neccessary any more to specify the path in every single Matlab script. Moreover, you can run your scripts on different machines without the need to adjust the path in the script on every system. When a new version of Vinci is released, switching to the new version of Vinci requires that you adjust the path to the Vinci package only once in your pathdef.m file.
In the following sections, we except that you have already added the Vinci Matlab package to your Matlab path (by hand or permanently).
Starting Vinci from Matlab
To start a new instance of Vinci from within Matlab, type
connection = Vinci.Connect();
This call will start Vinci and return a connection object of the type
Vinci.Connect
:
connection = Vinci.Connect(); whos connection % returns % Name Size Bytes Class Attributes % % connection 1x1 112 Vinci.Connect
This connection object is the central component of the Vinci interface. Every other object which communicates with Vinci will do this through the connection object.
You can call Vinci.Connect()
several times to start multiple instances of
Vinci. Each call returns a new connection object and the different Vinci
instances are independent of each other.
Connecting to a Running Instance of Vinci
You can connect to an already running instance of Vinci. This feature
requires that you start Vinci with the commandline option -S
(uppercase s
).
In this mode, Vinci will not open the default project, but instead show an
empty window and wait for connection requests. When started with -S
, Vinci’s
log view will contain a line similar to
opened TCPServer (port: 42456)
The number in this line is the network port, on which Vinci awaits Matlab’s connection request. To connect to Vinci from Matlab, supply this number as a parameter to the Vinci.Connect call:
connection = Vinci.Connect(42456);
The Vinci Package
All functions and classes used by the Vinci Matlab interface are stored within
a Matlab package with the name Vinci
. When you use components from this
package, you always have to prefix the component with Vinci.
. For example,
if you want to refer to the Image
class within the package, you have to
type Vinci.Image
. Using packages prevents name clashes between several
different functions or classes with identical names.
If you use a class or function often, you can import it. This way, it is not neccessary to specify the package name any more:
import Vinci.Connect connection = Connect();
To import all classes and functions, execute
import Vinci.*
Importing all components of a package can cause subtle bugs when a function or class in the path is hid by another function or class with the same name inside the module. Therefore, it is usually not a good idea to import all components of a package.
The Documentation
Our goal is to document all classes, properties, methods and functions
of the Vinci Matlab interface. We have not succeeded so far, as some
parts of the interface are still undocumented. Large parts, however,
already contain documentation describing the functionality of classes
and methods. To access this documentation from within Matlab, type
either help <component>
or doc <component>
in Vinci’s command prompt.
To access the documentation of the image class, type
help Vinci.Image
To see the documentation of the sendMessage method of class Connect, type
help Vinci.Connect.sendMessage
If you prefer an html version of the documentation, have a look at the Matlab API Documentation.
Optional Arguments
Many methods and functions provided by the Vinci interface have a list of optional arguments. You can specify these arguments as key-value pairs at the end of the function’s argument list. For example, the method Vinci.Image.createRoiPolygon() has the optional arguments =’Color’= and =’Rotation’= to initialize the color and rotation of the roi to specific values. You can supply these arguments as
Vinci.Image.createRoiPolygon('Color', [255 0 0], 'Rotation', pi/2);
The order, in which you supply the arguments is not important, therefore, you can also write
Vinci.Image.createRoiPolygon('Rotation', pi/2, 'Color', [255 0 0]);
If you do not supply an additional argument, Vinci will either set this argument to a default value or behave in a different way. For example, if you do not specify the number of the =’ImageBuffer’= when loading an image, Vinci will automatically choose a free image buffer for you. The default behaviour of optional arguments is documented in the documentation of the corresponding function or method.
Filepaths
There are several situations, in which you have to supply the path to a file. Often, Vinci - not Matlab - will try to read from or write to this file. Vinci’s current directory, however, does not neccessarily correspond to Matlab’s current directory. Therefore, it is dangerous to supply a filename using a relative path as Vinci might misinterpret the path.
Instead, convert relative paths to absolute paths using
the function Vinci.getAbsolutePath(relpath)
. This function can also resolve
the ~
character at the beginning of a path to the user’s home directory,
just like it is done in the unix shell. This feature will work on all platforms,
including Windows. So if the project file, you want to open is located in the
user’s home directory in a directory data, you can write
myProjectFile = Vinci.getAbsolutePath('~/data/project.vpx');
On linux, the home directory is located at /home/<username>/
. On Mac OS X,
it is /Users/<username>/
. On Windows, it will be either
C:\Documents and Settings\<username>
or C:\Users\<username>\
.
Creating a new Project or Loading an Existing One
When Matlab starts a new instance of Vinci, Vinci does not load a project. Instead, Vinci just shows an empty window. This allows you to either create a new, empty project or load an existing project, which initializes Vinci the way you like.
The following snippet starts a new Vinci instance and opens a new empty project:
connection = Vinci.Connect(); commands = Vinci.Commands(connection); commands.newProject();
To load an existing project file, type:
connection = Vinci.Connect();
commands = Vinci.Commands(connection);
commands.loadProject('/path/to/project-file.vpx');
The path to the file must be either absolute or relative to Vinci’s working directory, as explained in Filepaths.
Loading Images
To load an image, type
img = Vinci.Image.loadImage(connection, filename);
As we already explained in Filepaths, the filename must be absolute as Vinci and
not Matlab will try to load the image file. You can use Vinci.getAbsolutePath()
to
convert a path relative to Matlab’s working directory into
an absolute path.
By default, Vinci tries to guess the file format of an image file. This feature most often works, however, Vinci will not always choose the correct plugin. Therefore, it is a good idea to specify the image format explicitly if you know the image format of the file.
c = Vinci.Constants;
img = Vinci.Image.loadImage(connection, filename, 'ImageFormat', c.ImageTypes.ECAT7Image);
You can find the names of all supported file formats in
Vinci.Constants.ImageTypes
.
Both the connection
object and the filename
are mandatory arguments to the loadImage
function. Moreover, there are several optional arguments, you can use when loading an image.
Type
doc Vinci.Image.loadImage
for a list of all arguments available.
Getting a Handle to an Image in Vinci
Sometimes, you want to get a handle to an image, which has already
been loaded. This might be the case if you previously opened a project,
which does already contain images or if the user of your script loaded
images by hand into Vinci. If you know the number of the image buffer,
you can create a Vinci.Image
object and specify the image number in the
constructor.
#begin_src matlab img = Vinci.Image(connection, 0); #end_src
You can find the number of the image buffer in the blue bar above the image in Vinci.
If you need a list of all images loaded in Vinci, you can type
#begin_src matlab images = Vinci.Image.getAllImages(connection); #end_src
This function returns a vector of Vinci.Image
objects for
all images defined in Vinci. If you need a list of all image buffers
in Vinci (even the ones, which do not contain valid images), you
can set the optional second parameter includeUndefined
to true
.
#begin_src matlab imgs = Vinci.Image.getAllImages(connection, true); #end_src
Reading Metadata From an Image
Vinci loads an stores meta-information about your images, such as the
name of the patient, the date of the measure, the tracer used in a PET
measurement and so on. You can access this meta-information from Matlab
with the getMetaInformation()
method of the image class.
image = Vinci.Image.loadImage(connection, filename); metainformation = image.getMetaInformation();
The value returned by getMetaInformation()
is a struct object containing a
field for every element of meta-information.
metainfo = image.getMetaInformation(); fprintf('The patient''s name is %s', metainfo.PatientName); fprintf('The patient''s date of birth is %s', metainfo.PatientDOB);
You can query a list of all fields in the struct by typing
fieldnames = fieldnames(metainfo);
For every field in the struct returned by getMetaInformation()
, there
is also a property with the same name in the image class. Therefore, you
can also write
image = Vinci.Image.loadImage(connection, filename); fprintf('The patient''s name is %s', image.PatientName); fprintf('The patient''s date of birth is %s', image.PatientDOB);
This method is more convient to use then calling getMetaInformation()
.
It is, however, also slower when accessing multiple elements of meta-information,
as Matlab has to request each element individually.
Loading an Image Volume into Matlab
One strength of Matlab is that you can perform almost arbitrary
image processing tasks with it. You can combine this feature
with Vinci’s large number of supported image formats to easily
load and process images, as well as view and save the results back
to disk. The link between Vinci and Matlab is the method
Vinci.Image.getImageVolume
. This function returns the image volume
of any image in Vinci as a 3D array of float values.
image = Vinci.Image.loadImage(connection, filename); volume = image.getImageVolume(); % pixelsize is stored in mm pixelsize = image.PixelSize;
You can use the property PixelSize
to get the voxel dimensions
of the image.
Using the image volume and the pixel size, you can now manipulate the image in any way you like, i.e. segment it, apply filters or calculate statistics about the image.
Creating New Images and Cloning Images
When you modify the volume of an image, you usually want to
display and save the modified image in Vinci. You can change the
image volume of an existing image with the method
Vinci.Image.setImageVolume()
. Using this method, however, is
discouraged. Changing an image volume modifies the original image.
If you change the image and then save the project, you might
accidentally overwrite the original file and lose important data.
It is a much better idea to either create a new image or clone an
existing image with modified settings.
Creating a new image is the appropriate way if there is no image which you could clone. For example, if you use Vinci just to display images, you will most often open a new instance of Vinci just to show one image.
If you modify an existing image or create a new image, which is derived from an existing image, you should clone the original image. The cloned image will inherit all meta information from the original image, as well as the reslicing parameters and the color scale.
To create a new image, write
% compute an image volume volume = ones(128, 128, 64); pixelsize = [1 1 2]; newImage = Vinci.Image.createImageFromMemory(connection, volume, 'PixelSize', pixelsize);
To clone an existing image, type
volume = img1.getImageVolume(); pixelsize = img1.PixelSize; % compute a new volume [newVolume, newPixelSize] = someComputation(volume, pixelsize); newImg = img1.cloneImage(newVolume, 'PixelSize', newPixelSize);
Both functions, createImageFromMemory
and cloneImage
, have a number of additional arguments.
You can find out about these arguments by typing
help Vinci.Image.createImageFromMemory help Vinci.Image.cloneImage
in the command window.
Display Objects
Vinci provides a set of objects, which you can place on top of a displayed image and use for the evaluation of images or for the creation of illustrations
- regions of interest (rois), text annotations, profiles and measures. These
objects are called display objects.
You can both access display objects created in Vinci from within Matlab and create new display objects inside Matlab. Each display object is associated with exactly one image.
Creating Display Objects
To create a display object, write
displayObject = image.create*();
Here, image must be an object of type Vinci.Image and you must replace the asterisk (*) with the name of the display object, you want to create. The following table gives a list of all the display objects and their associated creation methods:
Method | Created Type | Description |
---|---|---|
createAnnotation() | Vinci.Annotation | Creates a new text annotation on top of the image. |
createProfile() | Vinci.Profile | Creates a new profile on top of the image. |
createMeasure() | Vinci.Measure | Creates a new distance measure tool on top of the image. |
createRoiRect() | Vinci.RoiRect | Creates a new rectangular roi on top of the image. |
createRoiEllipse() | Vinci.RoiEllipse | Creates a new ellipic roi on top of the image. |
createRoiPolygon() | Vinci.RoiPolygon | Creates a new polygonal roi on top of the image. |
createDisplayGroup() | Vinci.DisplayGroup | Creates a new display group on top of the image. |
You can call all display object creation methods without any arguments. In this
case, Vinci will set all properties of the created display object to some default
value. You can, however, also supply a number of optional arguments in the form of
key-value pairs to the create*
method. The following options are supported by
all display object types:
Property | Description |
---|---|
‘Name’ | The name of the display object. The name is not required to be unique. |
‘OrthoPart’ | The name of the ortho part (transaxial, coronal, sagittal), on which the display object should be displayed. Use the values in Vinci.Constants.OrthoParts when setting this options. |
‘Color’ | The color, which is used to display the display object. Colors are specified as triples [r, g, b] of integers between 0 and 255. |
‘Rotation’ | The rotation angle of the display objects. You must specify the angle in radians. The display object is rotated around it’s center. |
image = Vinci.Image.loadImage(connection, filename); orthoParts = Vinci.Constants.OrthoParts; roi1 = image.createRoiRect(); roi2 = image.createRoiEllipse('OrthoPart', orthoParts.Coronal); roi3 = image.createRoiPolygon('Color', [200 30 0], 'Rotation', pi/4); annotation = image.createAnnotation('Name', 'AnAnnotation'); measure = image.createMeasure('OrthoPart', orthoParts.Sagittal);
Querying Existing Display Objects
Each display object belongs to one image in Vinci. You can query all display
objects using the getDObjects()
method of the Vinci.Image
class:
image = Vinci.Image.loadImage(connection, filename); dobjects = image.getDObjects();
The most commonly used object type in Vinci is the roi. This is why a method
Vinci.Image.getRois()
exists, which only returns the rois belonging to an image:
image = Vinci.Image.loadImage(connection, filename); rois = image.getRois();
Display Coordinates
The position and size of a display object is given in display coordinates. An ortho view consists of several ortho displays, one for each displayed image. Each ortho display has one or several ortho parts. Usually, three ortho parts are shown - transaxial, coronal and sagittal. In the case of a zoomed view, however, only one ortho part is visible. The bottom left corner of such an ortho part has the coordinate (0,0). The upper-right corner is located at the coordinate (1,1). The positive x-axis runs from the left-hand side to the right-hand side of the display. The positive y-axis extends from the bottom to the top of the display. Values outside the range [0, 1] are valid, however, they lie outside the visible display. See figure XYZ for an illustration of the display coordinate system.
Defining Geometry
All display objects provide a way to specify the geometry of the display object. Since the nature of the geometry differs from display object type to display object type, there is not one way to specify the geometry for all display object types. The following subsections describe how to define the geometry of different display objects.
RoiRect and RoiEllipse
Rectangular and elliptic rois are both defined by the coordinates of the
lower-left corner of the roi and it’s width and height. You can query and set
the geometry using the geometry
property of both roi classes. The geometry
must be specified as a struct with the fields x
, y
, width
and height
.
rectangle = image.createRoiRect(); ellipse = image.createRoiEllipse(); geo = struct('x', 0.3, 'y', 0.5, 'width', 0.2, 'height', 0.4); rectangle.geometry = geo; ellipse.geometry = geo;
RoiPolygon
The geometry of polygonal rois is given by a list of points, which define the
corners of the polygon. You must specifiy the list as a 2xN matrix of float values.
You can query and set the geometry using the geometry
property.
polygon = image.createRoiPolygon();
geo = [0.3 0.4; 0.5 0.8, 0.8, 0.3]';
polygon.geometry = geo;
Profile and Measure
We define the geometry of profiles and measures by the position of the two
endpoints, called head and tail. The value supplied to the geometry property
must be a struct with two fields head
and tail
. Both fields must point to
another struct with the fields x
and y
:
profile = image.createProfile(); measure = image.createMeasure(); head = struct('x', 0.3, 'y', 0.8); tail = struct('x', 0.7, 'y', 0.1); geo = struct('head', head, 'tail', tail); profile.geometry = geo; measure.geometry = geo;
Annotation
The geometry of a text annotation is defined by the position of the
upper-left corner as well as the font size and font family. You can use
the properties position
, fontSize
and font
to set the geometry of
an annotation:
annotation = image.createAnnotation(); annotation.geometry = [0.4 0.6]; annotation.fontSize = 14; annotation.font = 'Arial';
Evaluating Rois
Vinci can calculate various statistics about the voxels inside a roi. You
can access these statistics from Matlab with the evaluateRoi()
method. This
method is available for all roi types.
image = Vinci.Image.loadImage(connection, filename); roi1 = image.createRoiRect(); roi2 = image.createRoiEllipse(); roi3 = image.createRoiPolygon(); statistics1 = roi1.evaluateRoi(); statistics2 = roi2.evaluateRoi(); statistics3 = roi3.evaluateRoi();
The value returned by evaluateRoi
is a struct object with the fields Average
,
StdDev
, Min
, Max
, Sum
and Pixels
.
statistics = roi.evalutateRoi();
fprintf('The mean of the values inside the roi is %f\n', statistics.Average);
Advanced Roi Statistics
Vinci can calculate the most commonly used statistics for rois. However, there may
be situations, in which you need different statistics. For example, for noisy
images, you may not want to use the minimum and maximum but instead the 5-th and
95-th percentile. In these situations, you can use the method getRoiValues()
to
query the individual pixel values inside the roi.
values = roi.getRoiValues();
percentile5 = quantile(values, 0.05);
percentile95 = quantile(values, 0.95);
fprintf('The 5-percentile is %f and the 95-percentile is %f\n', percentile5, percentile95);
getRoiValues()
returns a vector of float values.
Coregistration
Vinci supports coregistration of images of the same or varying modalities via the MMM tool. Starting with Vinci 4.01.0, you can remote control the MMM tool with Matlab. To create a new MMM tool for an ortho display, write
ORTHODISPLAY_NUM = 0;
ortho = Vinci.OrthoView.getFirstOrthoView(connection);
mmm = Vinci.MMMTool.createNewMMMTool(connection, ortho, ORTHODISPLAY_NUM);
mmm
is a handle to the MMM tool window. You can now start a co-registration
using the following lines of code:
mmmScheme = Vinci.Constants.HumanSchemes.GoodQualityPetMrPrecise;
mmm.coregisterHuman(refImg, reslImg, 'SchemeName', mmmScheme);
refImg
and reslImg
must both be objects of the type Vinci.Image
.
The above code will coregister the reslicing image reslImg
onto the reference image refImg
. The additional argument ‘SchemeName
’
selects the coregistration scheme, which should be used. You can find
valid coregistration schemes in Vinci.Constants.HumanSchemes
. Each
coregistration scheme in this struct corresponds to one entry in the
dropdown list at the top of the MMM tool window.
You can access the new transformation of the reslicing image with the
getResliceParameters()
method of the reslicing image:
parameters = reslImg.getResliceParameters();
Comments and further Development
We are excited about the new possibilities this Matlab interface
offers for scripting Vinci. Please let us know if you have suggestions
on how we can further improve it - it is generally possibly to remotely
control most features of Vinci (we need this ability for our automated
testing anyway) and the Matlab interface can be easily extended to
cover more functionality. Mail: vinci@nf.mpg.de