====== 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 [[http://nifti.nimh.nih.gov/|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 [[#mlrImageXform|transform]] images and still maintain the header information. There are also functions to automatically [[#mlrImageOrient|convert]] images to be in a canonical LPI orientation or easily [[#mlrImageReslice|reslice]] a volume to make a matching set of 2D inplanes for an epi image. These functions are built to load Nifti headers (using [[http://www.pc.rhul.ac.uk/staff/J.Larsson/software.html|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 [[#mlrImageHeaderLoad|mlrImage header]]. ====== mlrVol ====== **usage**: mlrVol([[#Specifying_image_to_load_with_mlrImageParseArgs|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 [[#Specifying_image_to_load_with_mlrImageParseArgs|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.
{{:mrtools:mlrvol1.png?600x342|}}
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|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
{{:mrtools:mlrvol2.png?600x342|}}
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 **L**eft to right, second from **P**osterior to anterior, third from **I**nferior 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|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
{{:mrtools:mlrvol3.png?800x645|}}
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:
{{:mrtools:mlrvol4.png?436x400|}}
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|mlrImageLoad]] routine that loads the image when you bring up the image. This is documented more completely in [[#Specifying_image_to_load_with_mlrImageParseArgs|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
{{:mrtools:mlrvol5.png?600x342|}}
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|mlrImageLoad]] and [[mlrImage#mlrImageXform|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([[#Specifying_image_to_load_with_mlrImageParseArgs|image to load]]\\ **e.g.**: [d h] = mlrImageLoad('image.hdr');\\ **purpose**: Loads the image data and an [[#mlrImageHeaderLoad|mlrImageHeader]]. ^ return argument ^ value ^ | d | matrix containing image data | | h | [[#mlrImageHeaderLoad|mlrImage header]] structure | ===== mlrImageHeaderLoad ===== **usage**: h = mlrImageLoad([[#Specifying_image_to_load_with_mlrImageParseArgs|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 [[http://nifti.nimh.nih.gov/nifti-1/|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 4x4 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 4x4 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 4x4 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 4x4 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 [[talairachCoordinates|talairach]] program. | ===== mlrImageSave ===== **usage**: mlrImageSave(filename,d,)\\ **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,);\\ **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 [[#Specifying_image_to_load_with_mlrImageParseArgs|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([[#Specifying_image_to_load_with_mlrImageParseArgs|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_image_to_load_with_mlrImageParseArgs|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^ function^handled by^example^ | 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 [[#mlrImageHeaderLoad|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.