Data I/O in Camino

1.  Dimensionality of data

We will refer to multi-component data as 4D. In the NIfTI standard, the fourth dimension is reserved for time series, and multicomponent images are actually 5D, where the fourth dimension has just one component. In other formats this is not the case, and some software will write multicomponent NIfTI images as 4D, which we interpret in the same way as a 5D image.

2.  General NIfTI I/O

Camino will read data from .nii, .hdr, or .mha files. The preferred format is NIfTI (.nii or .nii.gz). Voxel data can also be written in .nii.gz format by most programs. For example, we could create an FA image with

dtfit dwi.nii.gz dwi.scheme | fa -header dwi.nii.gz -outputfile fa.nii.gz

For multi-component data, we can write a 4D vector image.

dtfit dwi.nii.gz dwi.scheme | dteig -header dwi.nii.gz -outputfile dteig.nii.gz

Multi-component data will be written as a 4D image, with components in the same order as the Camino raw data equivalent (see the file formats page for details). Thus if you do

dtfit dwi.nii.gz dwi.scheme -outputfile dt.nii.gz

the file dt.nii.gz contains the 8 components normally produced by dtfit. See below for details on how to convert DT data to and from the standard 6-component symmetric matrix format. Internally, no conversion is required and we can do

fa -inputfile dt.nii.gz -outputfile fa.nii.gz

3.  DWI data

NIfTI data may be read directly into Camino as above, however it may be necessary to convert to voxel order in order to conserve RAM. For example, you can do

dtfit dwi.nii.gz dwi.scheme -outputfile dt.Bdouble

But this will require enough RAM to store all the DWI data. Converting to voxel order with image2voxel and storing the output file is more efficient on memory at the expense of disk space.

image2voxel -4dimage dwi.nii.gz -outputfile dwi.vo.Bfloat 
dtfit dwi.vo.Bfloat dwi.scheme > dt.Bdouble

Sometimes we may have or want 3D volumes instead of one 4D image. For example, we might want to coregister all the DWI volumes to correct for motion. You can split them with split4dnii. You can use a series of 3D images with image2voxel by writing a text file listing the 3D images in order. For example, split a 60-component image :

split4dnii -inputfile image.nii.gz -outputroot 3d_

produces 3d_0001.nii.gz through 3d_0060.nii.gz. To use these images with image2voxel, do something like

ls 3d_* > imagelist.txt; image2voxel -imagelist imagelist.txt | dtfit - scheme.txt

3.1  Converting DICOM data

Camino doesn't have any support for reading DICOM data. There are multiple options for DICOM conversion, many of us use dcm2nii, which is part of the mricron package by Chris Rorden. This program will give you a 4D nii file that you can feed to image2voxel. If possible, it will also output the b-values and b-vectors associated with the acquisition. You can convert these to a Camino scheme file with fsl2scheme. Note that the units of the b-values will be those used by the scanner, typically s / mm2. Some Camino programs are sensitive to the choice of units (eg datasynth), so the default options may not work with some scheme files. You can avoid this issue by scaling your b-values into s / m2 using fsl2scheme.

4.  NIfTI tensor data

If you have NIfTI tensor data, you can convert it with nii2dt:

nii2dt -inputfile dt.nii > dt.Bdouble

The NIfTI tensor format contains a bit less information than the Camino format (ie, no exit code or unweighted signal), so these will be set to zero in the output unless you provide them on the command line. You can convert back to NIfTI format with dt2nii.

You can also use NIFTI DT images directly, for example:

fa -inputfile dt.nii.gz -outputfile fa.nii.gz

DT data written by Camino will be an 8-component 4D image, not the 6-component symmetric matrix format. To get DTs in the format expected by programs such as DTI-TK and ANTs, use dt2nii:

dt2nii -inputfile dt.Bdouble -outputroot dt_

This will output the DT as a symmetric matrix, as well as producing 3D images of the exit code and log of the unweighted signal.

4.1  Coordinate system of diffusion tensor data

The header transformation tells us where a position on the voxel grid would be in physical space, but the orientation of diffusion tensors is determined by the scheme file.

The gradient directions reported by scanners are usually described in the physical space of the magnet. One of the nice features of dcm2nii is that it will attempt to convert gradient directions into the coordinate system of the image, which is what we need for Camino. Whether or not you use dcm2nii, it's important to use pdview to check the tensor orientations before attempting tractography or anything else that depends on the orientation information. See the DT tutorial for more examples.

5.  Dealing with raw data

Raw data can be manipulated in various ways. You may need to change the ordering of data, the endianness, or the data type. Most of these issues relate to handling raw DWI data. Inside the Camino pipelines, the defaults should be sufficient for most users. To convert raw data back to NIfTI, see the section on Exporting raw data to NIfTI.

5.1  Ordering data

Probably the most common task is to re-order DWI data from image to voxel order. Voxel-ordered data can be streamed, saving memory, and split up easily, allowing for parallel processing. You can get raw data into and out of scanner order with the scanner2voxel and voxel2scanner commands. Since these commands expect to deal with mostly raw data, they read and write floats by default (see below). You can change this behaviour with -inputdatatype and -outputdatatype options. For example:

scanner2voxel -voxels 983040 -components 60 -inputfile ScannerOrder.img -inputdatatype short > VoxelOrder.Bfloat

where -components specifies the number of volumes in the 4D input and -voxels specifies the number of voxels (ie, X×Y×Z, where X, Y, Z are the dimensions of the image).

5.2  Data type

By default, DWI data is expected to be float - big-endian, 32-bit decimals. Programs such as scanner2voxel and modelfit expect float data by default. If you pass raw DWI data explicitly (eg, giving DWI data to track) it is also assumed to be float.

Processed raw image data is assumed to be double - big-endian, 64-bit decimals. Programs such as fa or dteig expect double data. You can change the input and output data types for most programs with -inputdatatype and -outputdatatype. These flags don't apply to non-image objects, such as fiber tracts. Some programs read images with headers (eg image2voxel), these do not need the -inputdatatype flag.

5.3  Endianness

Following Java convention, Camino writes raw data in big-endian format. Camino will never write little-endian data except when writing images with headers that indicate endianness (eg, when writing a NIfTI image). When reading data, Camino assumes big-endian input unless told otherwise by an image header. Therefore if the file ScannerOrder.img is little-endian, we need to reverse the endianness. Note that although ScannerOrder.img is part of an Analyze image pair, when we use it in the context above, it is just a binary file like any other. Therefore we use shredder:

cat ScannerOrder.img | shredder 0 -2 0 | scanner2voxel -voxels 983040 -components 60 \\
            -inputdatatype short > VoxelOrder.Bfloat

The shredder command reads periodic chunks of data from binary files. With a negative read size, the endianness is reversed in the output. Note that we don't use any data type commands with shredder because it only deals in bytes. You read them, optionally reverse the order, then output. The short datatype is implicit in the chunk size (2 bytes). If we were reading floats, the chunksize would be 4. In general, you can reverse byte order in a file by doing shredder 0 -size 0, where size is 2 for short, 4 for int or float, 8 for long or double.

5.4  DWI conversion detail example

The example data set is the monkey data from the DTI tutorial - see the link for instructions to download the data. Instead of using image2voxel, we'll go through the conversion step by step. To save typing, let's rename the file

gunzip DRCMR_ActiveAx4CCfit_E2503_Mbrain1_B1925_3B0_ELEC_N90_Scan1_DIG.nii.gz

mv DRCMR_ActiveAx4CCfit_E2503_Mbrain1_B1925_3B0_ELEC_N90_Scan1_DIG.nii dwi.nii

Camino expects big-endian binary data. The data file should have no header and be in voxel order, meaning the data for each voxel is stored together. If we consider each DWI measurement an "image", then the ordering of the data file is:

image 1 voxel 1
image 2 voxel 1
image N voxel 1
image 1 voxel 2
image 2 voxel 2
image N voxel 2
image 1 voxel M
image N voxel M
The nifti file contains a header followed by raw image data. We can look at the header to see some information we need.

niftiheader -readheader dwi.nii

Of particular importance are the data dimensions (128x256x3), the data type (short) and the endianness of the data (little endian, or Intel byte order).

To make the conversion, start by specifying the size of the data set:

export XSIZE=128;
export YSIZE=256;
export ZSIZE=3;
# This is the number of images in the acquisition protocols
# ie diffusion weighted images plus unweighted images.
export COMPONENTS=93;

Strip off the NIfTI header to make a raw data file:

tail -c $((XSIZE*YSIZE*ZSIZE*COMPONENTS*2)) dwi.nii > dwi.raw

Now we have the raw data file in volumetric order:

image 1 voxel 1
image 1 voxel 2
image 1 voxel M
image 2 voxel 1
image 2 voxel 2
image 2 voxel M
image N voxel 1
image N voxel M
So we need to convert it to voxel order, which we can do using the camino command scanner2voxel?, and switch the byte ordering from little endian to big endian, which we can do using the camino command shredder:

cat dwi.raw | shredder 0 -2 0 | scanner2voxel \
-voxels $((XSIZE*YSIZE*ZSIZE)) -components $COMPONENTS -inputdatatype short > DRCMR_B1925.Bfloat

The shredder command reverses the order of each two-byte chunk. The chunk size is two bytes because the input data is short, if it was float we would do shredder 0 -4 0.

5.5  Exporting raw data to NIfTI

The voxel2image command will export raw data back to an image or series of images. The format of the image or images is determined by the header file that is passed at run time.

If you need a particular component of an image, you can either write the data as 3D images with voxel2image, or extract the values you want with shredder. For example, if we wanted only the principal eigenvalue from dteig, we could call

cat dt.Bdouble | dteig | shredder 0 8 $((11*8)) ]] | voxel2image -components 1 -header dwi.nii.gz -outputroot ad.nii.gz

The dt2nii command has special procedures for exporting tensor or multitensor data to NIfTI format.