Overview

mlrImage is a set of Matlab commands that can be used for loading, manipulating, viewing and saving MRI data. These functions are intended to load, maintain and save the orientation and alignment information in the headers - particularly the NIfTI header information. For instance, you can view volumes with the viewer mlrVol and if the orientation information in the qform is correct, it will display images correctly in coronal, sagittal and axial views with the labels (e.g. left vs right) labeled correctly. You can also transform images and still maintain the header information. There are also functions to automatically convert images to be in a canonical LPI orientation or easily reslice a volume to make a matching set of 2D inplanes for an epi image. These functions are built to load Nifti headers (using cbiNifti), but can also handle filetypes for Varian/Agilant consoles and in principle can be easily extended for other file types which support loading and saving of the information that is made accessible in the matlab mlrImage header.

mlrVol

usage: mlrVol(image to load);
e.g.: mlrVol('image.hdr');
purpose: Volume viewer to display volume multi-dimensional data (usually 3D volumes or 4D epi sequences)

You can specify the volume to load using either the filename, view/scanNum/groupNum, select from a dialog box in the current or canonical directory, or from a struct. See mlrImageParseArgs for details.

If qform information exists (from a nifti header) it will orient the axis in LPI and label axis correctly (left/right, posterior/anterior, inferior/superior). For example:

>> mlrVol jg041001.hdr

Note that in this and all examples, we can always call mlrVol like:

>> mlrVol('jg041001.hdr');

but when we just need to type all string arguments, I prefer the first form which is easier to type.

Note how the planes are correct for the image (first panel - sagittal, second panel - coronal, third panel - axial). Also the axis labels, left/right, inferior/superior, anterior/posterior are correct as well. All this information is interpreted from the qform in the nifti header by the function mlrImageGetAxisLabels. The labels X,Y,Z refer to the first, second and third dimensions of the data.

If you mouse over the image, you can display the image intensity value at the bottom of the figure and the current coordinates (note that you can control the alternate coordinates at right - in this example showing Talairach coordinates by using the Controls button). If you hit the buttons X, Y and Z you will see the image animate in that dimension. Mouse clicking on any of the images will update the other views to display the matching slice.

If you want to view the image in its native orientation (i.e. order it is written into the matrix), then set the input argument imageOrientation=1. For example:

>> mlrVol jg041001.hdr imageOrientation=1

Note how for this example, the different panels are no longer oriented in the standard orientation. This is because it is not using the qform information from the header to orient the image correctly. Instead it is just displaying according to the ordering of dimensions that the image happens to be oriented in. If your image happens to be LPI (First dimension goes from Left to right, second from Posterior to anterior, third from Inferior to superior), then the image will display in the same way as when you display according to the qform. Note that if you want to convert your image into an LPI ordering (so that it can be displayed properly in some other program that expects this orientation) you can use the program mlrImageOrient.

With two filename arguments mlrVol will show the alignment between the two images. It computes the alignment based on the sforms if they are both set or the qforms otherwise. If neither one is set will display with an identity alignment. For example:

>> mlrVol jg041001.hdr jg060918+04+t12Dmprage27sl.hdr

The top row shows the volume with the inplanes as a semi-translucent red overlay. The bottom row shows the inplanes interpolated to match the volume (based on the alignment).

A dialog box allows you to fiddle manually with the alignment:

Most of the controls should be fairly self-explanatory, but see the help in the dialog for more info. The displayInterpolated checkbox controls whether the bottom row shows the inplanes interpolated to match the volume in the first row or not.

Note that you can pass arguments to the mlrImageLoad routine that loads the image when you bring up the image. This is documented more completely in mlrImageParseArgs. But, briefly, you can pass arguments that grab a subset of the image by setting (xMin, xMax, yMin, yMax, zMin and zMax), swap, flip or rotate the image with: swapXY, swapXZ, swapYZ, rotateXY, rotateXZ, rotateYZ, shiftX, shiftY, shiftZ).

For example,

>>  mlrVol jg041001.hdr xMin=20 xMax=240 swapXY=1 rotateXY=-10

You should be able to see that the image has been trimmed to 20:240 in the x dimension and rotated in the XY plane by 10 degrees (look at axial image). Note that even though we have swapped the X and Y axis in the image that the volume is displaying the same as before - this is because the qform has been correctly updated so mlrVol is orienting the volume correctly. You can tell that the X and Y axes have been swapped by comparing the labels with the images above and noting that, for example, the horizontal axis for the sagittal image is now the x rather than the y dimension. If you need finer control over the order in which the transformations are performed or whether they only apply to the header or the data, then see the functions mlrImageLoad and mlrImageXform.

You can also set the verbose level by setting the argument 'verbose=1'. Use 0 for quiet. 1 for normal. 2 for detailed info.

Load and save functions

mlrImageLoad

usage: [d h] = mlrImageLoad(image to load
e.g.: [d h] = mlrImageLoad('image.hdr');
purpose: Loads the image data and an mlrImageHeader.

return argument value
d matrix containing image data
h mlrImage header structure

mlrImageHeaderLoad

usage: h = mlrImageLoad(image header to load)
e.g.: h = mlrImageLoad('image.hdr');
purpose: Loads the header of the image.

return argument value
h header structure

mlrImage headers contain information about the image including orientation information (based in part on the Nifti standard. The fields are as follows.

Field name type purpose
nDim scalar set to the number of dimensions in the data
dim array of length nDim contains the size of each dimension in the data. Note that this is different from nifti in that the first element does not contain the number of dimensions (nDim), instead each element contains the size in that dimension. Should always be equal to size(data)
pixdim array of length nDim Contains the size in mm of each dimension. If the dimension is the volume dimension, then should contain the time it took to acquire. If the information is unknown these values will be set to nan.
qform a 4×4 homogenous transform matrix Specifies the xform from the image coordinates to the magnet coordinates. Same as a nifti header qform when qform_code = 1. Will be empty if no such information exists.
sform a 4×4 homogenous transform matrix Specifies the xform from the image coordinates to the magnet coordinates for the canonical volume. This is the same as a nifti header qform when sform_code = 1. Will be empty if no such info exists.
vol2mag a 4×4 homogenous transform matrix This is the xform from the canonical volume coordinates to the magnet coordinates for the canonical. This is useful for checking which volume the image was aligned to (i.e. where it got the sform from). It is also useful for when trying to compute the talairach coordinates. Will be empty if no such info exists.
vol2tal a 4×4 homogenous transform matrix This is the xform from the canonical volume coordinates to the talairach coordinates for the canonical. Note that we keep this matrix since it allows us to go back and change the talairach points on the canonical volume and then easily redo the tal xforma for the image by simply replacing this matrix. To compute the xform from the image coordinates to talairach coordiates, you can do: img2tal = vol2tal * inv(vol2mag) * sform * shiftOriginXform; Will be empty if no such info exists.
ext three letter string The filename extension
filename string The filename
type string What type of file the image is (e.g. Nifti, data, fid, fdf, sdt, etc.)
base struct An mlr base structure if one is associated with the file. Note that fields like vol2mag and vol2tal come from the base structure rather that the nifti header since nifti can't hold more than two forms at a time (form and storm)
talInfo struct If non-empty contains the fields (AC,PC,SAC,IAC,PPC,AAC,LAC,RAC) which contain the coordinates of these talairach landmark points. This typically comes from the talairach program.

mlrImageSave

usage: mlrImageSave(filename,d,<h>)
e.g.: h = mlrImageLoad('image.hdr',d,h);
purpose: Saves an image

input argument value
filename The filename to save to. Note that the extension specifies what type of output to save to. If the extension is .hdr, .img or .nii it will save a nifti image. An SDT/SPR or EDT/EPR pair is saved out if the extension is one of .sdt, .spr, .edt, .epr
d The image data matrix
h The mlr header structure. This should be a header returned by mlrImageLoad or mlrImageHeaderLoad. This argument can be omitted in which case a default header is created.

mlrImageHeaderSave

usage: mlrImageHeaderSave(filename,h)
e.g.: h = mlrImageLoad('image.hdr',h);
purpose: Saves an image hearer

input argument value
filename The filename to save to
h The mlr header structure.

Image manipulation functions

mlrImageReslice

usage: [d h] = mlrImageReslice(canonical image,epi image,<resFactor>);
purpose: Creates a new set of images from the canonical image that match the slice orientation of the epi images. Note that you should run mrAlign to make sure that the canonical and the epi images are aligned. The default resolution is twice the inplane resolution of the volume, but this can be changed by setting the optional argument resFactor. Note that this uses mlrImageParseArgs to specify the images you wanted to use as input.
e.g.: [d h] = mlrImageReslice('canonical.hdr','epi.hdr');
e.g.: It may also be convenient to bring up dialog boxes to select the files you want by doing: [d h] = mlrImageReslice('canonical','.');

Once you have made the resliced inplanes, you may wish to save them by using mlrImageSave:

[d h] = mlrImageReslice('canonical.hdr','epi.hdr');
mlrImageSave('inplane.hdr',d,h);
argument name purpose
resFactor sets the scaling factor to reslice. For example, to make inplanes that have 4 times the resolution in plane and twice the resolution in the slice dimension, you would do [d h] = mlrImageReslice('canonical.hdr','epi.hdr','resFactor=[4 4 2]');

mlrImageXform

usage: [d h] = mlrImageXform(image header to load,commands);
purpose: Can do various transformations on an image, respecting the xform information in the header. i.e. if you swap X and Y coordinates it will also swap the qform and sform information.
e.g.: [d h] = mlrImageXform('image.hdr','swapXY=1','flipZ=1','shiftX=13.2',rotateXY=30');

Returns a data and header pair. The available commands are as follows:

command purpose e.g.
swapXY Swaps the image in the X and Y dimensions. [d h] = mlrImageXform('image.hdr','swapXY=1');
swapXZ Swaps the image in the X and Z dimensions. [d h] = mlrImageXform('image.hdr','swapXZ=1');
swapYZ Swaps the image in the Y and Z dimensions. [d h] = mlrImageXform('image.hdr','swapYZ=1');
flipX Flips the image in the X dimension [d h] = mlrImageXform('image.hdr','flipX=1');
flipY Flips the image in the Y dimension [d h] = mlrImageXform('image.hdr','flipY=1');
flipZ Flips the image in the Z dimension [d h] = mlrImageXform('image.hdr','flipZ=1');
shiftX Shifts the image in the x-dimension by the passed in number of voxels. Values can be fractions of a voxel. [d h] = mlrImageXform('image.hdr','shiftX=-10');
shiftY Shifts the image in the y-dimension by the passed in number of voxels. Values can be fractions of a voxel. [d h] = mlrImageXform('image.hdr','shiftY=-10');
shiftZ Shifts the image in the z-dimension by the passed in number of voxels. Values can be fractions of a voxel. [d h] = mlrImageXform('image.hdr','shiftZ=-10');
rotateXY Rotates the image by the passed in number of degrees in the XY plane [d h] = mlrImageXform('image.hdr','rotateXY=30');
rotateXZ Rotates the image by the passed in number of degrees in the XZ plane [d h] = mlrImageXform('image.hdr','rotateXZ=30');
rotateYZ Rotates the image by the passed in number of degrees in the YZ plane [d h] = mlrImageXform('image.hdr','rotateYZ=30');
interpMethod Set to the interp method desired for rotations and shift. Can be anything valid for interpn. Defaults to linear [d h] = mlrImageXform('image.hdr','rotateXY=30','interpMethod=Nearest');
applyToHeader Set to zero if you want the above shift, swap or rotate commands to not apply to the image header (and therefore apply only to the data). Defaults to 1. [d h] = mlrImageXform('image.hdr','swapXY=1','applyToHeader=0');
applyToData Set to zero if you want the above shift, swap or rotate commands to not apply to the image data (and therefore apply only to the header). Defaults to 1. [d h] = mlrImageXform('image.hdr','swapXY=1','applyToData=0');

mlrImageOrient

usage: [d h] = mlrImageOrient(orientation,image);
purpose: Reorients an image into a standard orientation like LPI.
e.g.: [d h] = mlrImageOrient('LPI','canonical.hdr');

input argument purpose
orientation sets what orientation to reorient the volume into. Should be a three letter string where the first letter specifies the order of the first dimension, the second letter the second dimension, etc. The letters can be any one of L for Left to right, R for Right to left, P or A for Posterior/Anterior, S or I for Superior/Inferior.
image an image specified in any way allowed by mlrImageParseArgs

Info functions

mlrImageGetAxisLabels

usage: axisLabels = mlrImageGetAxisLabels(xform);
purpose: This function uses the passed in xform (e.g. a qform) to determine in which direction each axis of the image goes. Note that the assumption is that the matrix conforms to the Nifti standard, so the identity matrix will be an LPI orientation.
e.g.: axisLabels = mlrImageGetAxisLabels(xform);

The return argument axisLabels contains the follwing fields

field name type purpose
labels cell array of 3 strings for each axis Readable labels for each axis. e.g. 'left ← X → right'
dirLabels cell array of 3 cell arrays for each axis which contains 2 strings A cell array with two strings for each direction (-/+) for each axis. That is, for example, the two strings will be 'left' and 'right'.
mapping array of 3 scalars is the map of each axis to the closest axis in the magnet space. That is each element is the axis in the image space and what axis it corresponds to in the magnet space.
reverseMapping array of 3 scalars is the inverse of mapping
dir array of 3 scalars is the direction (i.e. 1 or -1) in which that axis goes in the magnet space.
orient 3 letter string represents the axis orientation (like LPI)

Helper functions

mlrImageParseArgs

This function allows other functions like mlrVol, mlrImageLoad, mlrImageHeaderLoad, mlrImageReslice, mlrImageXform to accept various ways of specifying the image to load.

Using mlrImageParseArgs in a function

mlrImageParseArgs will turn a varargin variable into two separate cell arrays. The first, imageArgs, contains one element for each image found in varargin. The second, otherArgs, contains all the other args.

function myImageFun(varargin)

[imageArgs otherArgs] = mlrImageParseArgs(varargin);
verbose = [];
getArgs(otherArgs,{'verbose=1'});

Note that imageArgs simply contains a desired list of images. It does not check to see if the file exists. For that, you can use mlrImageIsImage:

for iImage = 1:length(imageArgs)
  if ~mlrImageIsImage(imageArgs{iImage})
    disp(sprintf('Could not open image: %s',mlrImageArgFilename(imageArgs{iImage})));
  end
end

Note above, the use of mlrImageArgFilename which turns elements on the imageArgs list into printable names (recall that mlrImageParseArgs can be used with data structures and the likes which are not simple filenames and so each element imageArgs is not a filename string. Instead, each element is a structure that can be understood my mlrImageLoad.

Specifying image to load with mlrImageParseArgs

The most basic way is to specify the name of the image (this and all further examples is for mlrVol, but will work with any of the functions that use mlrImageParseArgs):

mlrVol image.hdr

The filename extension specifies the file type to load. Currently accepted file types are:

extension file type
hdr, img, nii Nifti
fid Varian/Agilant fid
img Varian/Agilant FDF
sdt/spr/edt/epr RIKEN BSI basic text-based parameter header file and binary data internal formats based on “Stimulate”

You can also bring up a dialog box selection to choose from the volumeDir:

mlrVol canonical

Or the current dir

mlrVol .

You can also specify a particular scan from an MLR directory:

v = newView;
mlrVol(v,'scanNum=3','groupNum=1');

Or a data matrix or structure containing a data matrix in the field d or data:

d = rand(100,100,100);
mlrVol(d)

x.data = rand(100,100,100);
mlrVol(x);

You may also specify a data matrix and mlrImage header pair:

[d h] = mlrImageLoad('image.hdr');
mlrVol(d,h);

With any of these forms, you can also specify one or more arguments that can change various things about the image:

argument name functionhandled byexample
orient orients the image into a standard orientation like LPI - only works for an image with a valid qform (i.e. not if you just load an image matrix) mlrOrient mlrVol('image.hdr','orient=LPI');
xMin Crops the image in the x-dimension to begin with the passed in value mlrImageLoad mlrVol('image.hdr','xMin=10');
xMax Crops the image in the x-dimension to end with the passed in value mlrImageLoad mlrVol('image.hdr','xMax=120');
yMin Crops the image in the y-dimension to begin with the passed in value mlrImageLoad mlrVol('image.hdr','yMin=10');
yMax Crops the image in the y-dimension to end with the passed in value mlrImageLoad mlrVol('image.hdr','yMax=120');
zMin Crops the image in the z-dimension to begin with the passed in value mlrImageLoad mlrVol('image.hdr','zMin=10');
zMax Crops the image in the z-dimension to end with the passed in value mlrImageLoad mlrVol('image.hdr','zMax=120');
swapXY Swaps the image in the X and Y dimensions. mlrImageXform mlrVol('image.hdr','swapXY=1');
swapXZ Swaps the image in the X and Z dimensions. mlrImageXform mlrVol('image.hdr','swapXZ=1');
swapYZ Swaps the image in the Y and Z dimensions. mlrImageXform mlrVol('image.hdr','swapYZ=1');
flipX Flips the image in the X dimension mlrImageXform mlrVol('image.hdr','flipX=1');
flipY Flips the image in the Y dimension mlrImageXform mlrVol('image.hdr','flipY=1');
flipZ Flips the image in the Z dimension mlrImageXform mlrVol('image.hdr','flipZ=1');
shiftX Shifts the image in the x-dimension by the passed in value mlrImageXform mlrVol('image.hdr','shiftX=-10');
shiftY Shifts the image in the y-dimension by the passed in value mlrImageXform mlrVol('image.hdr','shiftY=-10');
shiftZ Shifts the image in the z-dimension by the passed in value mlrImageXform mlrVol('image.hdr','shiftZ=-10');
rotateXY Rotates the image by the passed in number of degrees in the XY plane mlrImageXform mlrVol('image.hdr','rotateXY=30');
rotateXZ Rotates the image by the passed in number of degrees in the XZ plane mlrImageXform mlrVol('image.hdr','rotateXZ=30');
rotateYZ Rotates the image by the passed in number of degrees in the YZ plane mlrImageXform mlrVol('image.hdr','rotateYZ=30');
interpMethod Set to the interp method desired for rotations and shift. Can be anything valid for interpn. Defaults to linear mlrImageXform mlrVol('image.hdr','rotateXY=30','interpMethod=Nearest');
applyToHeader Set to zero if you want the above shift, swap or rotate commands to not apply to the image header (and therefore apply only to the data). Defaults to 1. mlrImageXform mlrVol('image.hdr','swapXY=1','applyToHeader=0');
applyToData Set to zero if you want the above shift, swap or rotate commands to not apply to the image data (and therefore apply only to the header). Defaults to 1. mlrImageXform mlrVol('image.hdr','swapXY=1','applyToData=0');
kspace Loads the kspace data instead of the image data. Only available for Agilant/Varian fid files mlrImageLoad mlrVol('mprage01.fid','kspace=1');
movepro Shifts the data in the read-out direction by the number of voxels specified. This is done by adding the appropriate amount of phase in k-space to the data. Only available for Agilant/Varian fid files mlrImageLoad mlrVol('mprage01.fid','movepro=-30');
movepss Shifts the data in the second phase-enocde direction of a 3D image by the number of voxels specified. This is done by adding the appropriate amount of phase in k-space to the data. Only available for Agilant/Varian fid files mlrImageLoad mlrVol('mprage01.fid','movepro=-30');
rescale Scales the output of the image to between 0 and the value rescale is set to. For example (and by default with mlrImageLoad, you can rescale the value to between 0 and 255. Note that the numbers will still be floating point so that precision is not lost. This may help with some programs like FreeSurfer which don't handle very small image values well. mlrImageLoad mlrVol('image.hdr','rescale=1024');

Note that if you are specifying multiple images, the above parameters refer only to the prior image. For example:

mlrVol('image1.hdr','swapXY=1','image2.hdr','flipY=1');

The above will have image1 with swapped XY axis and image2 with the Y dim flipped.

mlrImageArgFilename

usage: str = mlrImageArgFilenames(imageArg);
purpose: Turns an imageArg from mlrImageParseArgs into a printable string.
e.g.:

[imageArgs otherArgs] = mlrImageParseArgs(varargin);
str = mlrImageArgFilenames(imageArgs{1});
disp(str);

mlrImageIsImage

usage: tf = mlrImageIsImage(filename);
purpose: Returns true if the named image exists or false otherwise. If filename does not have an extension than the mrGetPref('niftiFileExtension') is used. Can also handle imageArgs returned by mlrImageParseArgs.

mlrImageIsHeader

usage: [tf h] = mlrImageIsHeader(h);
purpose: Returns true if the passed in header is a valid mlrImageHeader. If the output value h is received then will add any missing fields to the h structure with default values.

mlrImageGetNiftiHeader

usage: hdr = mlrImageGetNiftiHeader(h);
purpose: Returns a nifti header hdr that corresponds to hte mlrImage header h.