NiBabel

Access a cacophony of neuro-imaging file formats

Table Of Contents

Previous topic

parrec

Next topic

eulerangles

Reggie -- the one

trackvis

Read and write trackvis files

DataError Error in trackvis data
HeaderError Error in trackvis header
TrackvisFile(streamlines[, mapping, ...]) Convenience class to encapsulate trackvis file information
TrackvisFileError Error from TrackvisFile class
aff_from_hdr(trk_hdr[, atleast_v2]) Return voxel to mm affine from trackvis header
aff_to_hdr(affine, trk_hdr[, pos_vox, set_order]) Set affine affine into trackvis header trk_hdr
empty_header([endianness, version]) Empty trackvis header
read(fileobj[, as_generator, points_space]) Read trackvis file, return streamlines, header
write(fileobj, streamlines[, hdr_mapping, ...]) Write header and streamlines to trackvis file fileobj

DataError

class nibabel.trackvis.DataError

Bases: exceptions.Exception

Error in trackvis data

__init__()

x.__init__(...) initializes x; see help(type(x)) for signature

HeaderError

class nibabel.trackvis.HeaderError

Bases: exceptions.Exception

Error in trackvis header

__init__()

x.__init__(...) initializes x; see help(type(x)) for signature

TrackvisFile

class nibabel.trackvis.TrackvisFile(streamlines, mapping=None, endianness=None, filename=None, points_space=None, affine=None)

Bases: object

Convenience class to encapsulate trackvis file information

Parameters:

streamlines : sequence

sequence of streamlines. This object does not accept generic iterables as input because these can be consumed and make the object unusable. Please use the function interface to work with generators / iterables

mapping : None or mapping

Mapping defining header attributes

endianness : {None, ‘<’, ‘>’}

Set here explicit endianness if required. Endianness otherwise inferred from streamlines

filename : None or str, optional

filename

points_space : {None, ‘voxel’, ‘rasmm’}, optional

Space in which streamline points are expressed in memory. Default (None) means streamlines contain points in trackvis voxmm space (voxel positions * voxel sizes). ‘voxel’ means points are in voxel space (and need to be multiplied by voxel size for saving in file). ‘rasmm’ mean the points are expressed in mm space according to the affine. See read and write function docstrings for more detail.

affine : None or (4,4) ndarray, optional

Affine expressing relationship of voxels in an image to mm in RAS mm space. If ‘points_space’ is not None, you can use this to give the relationship between voxels, rasmm and voxmm space (above).

__init__(streamlines, mapping=None, endianness=None, filename=None, points_space=None, affine=None)
classmethod from_file(klass, file_like, points_space=None)
get_affine(atleast_v2=None)

Get affine from header in object

Returns:

aff : (4,4) ndarray

affine from header

atleast_v2 : None or bool, optional

See aff_from_hdr docstring for detail. If True, require valid affine in vox_to_ras field of header.

Notes

This method currently works for trackvis version 1 headers, but we consider it unsafe for version 1 headers, and in future versions of nibabel we will raise an error for trackvis headers < version 2.

set_affine(affine, pos_vox=None, set_order=None)

Set affine affine into trackvis header

Affine is mapping from voxel space to Nifti RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior. Sets affine if possible, and voxel sizes, and voxel axis ordering.

Parameters:

affine : (4,4) array-like

Affine voxel to mm transformation

pos_vos : None or bool, optional

If None, currently defaults to False - this will change in future versions of nibabel. If False, allow negative voxel sizes in header to record axis flips. Negative voxels cause problems for trackvis (the application). If True, enforce positive voxel sizes.

set_order : None or bool, optional

If None, currently defaults to False - this will change in future versions of nibabel. If False, do not set voxel_order field in trk_hdr. If True, calculcate voxel_order from affine and set into trk_hdr.

Returns:

None :

to_file(file_like)

TrackvisFileError

class nibabel.trackvis.TrackvisFileError

Bases: exceptions.Exception

Error from TrackvisFile class

__init__()

x.__init__(...) initializes x; see help(type(x)) for signature

aff_from_hdr

nibabel.trackvis.aff_from_hdr(trk_hdr, atleast_v2=None)

Return voxel to mm affine from trackvis header

Affine is mapping from voxel space to Nifti (RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior.

Parameters:

trk_hdr : mapping

Mapping with trackvis header keys version. If version == 2, we also expect vox_to_ras.

atleast_v2 : None or bool

If None, currently defaults to False. This will change to True in future versions. If True, require that there is a valid ‘vox_to_ras’ affine, raise HeaderError otherwise. If False, look for valid ‘vox_to_ras’ affine, but fall back to best guess from version 1 fields otherwise.

Returns:

aff : (4,4) array

affine giving mapping from voxel coordinates (affine applied on the left to points on the right) to millimeter coordinates in the RAS coordinate system

Notes

Our initial idea was to try and work round the deficiencies of the version 1 format by using the DICOM orientation fields to store the affine. This proved difficult in practice because trackvis (the application) doesn’t allow negative voxel sizes (needed for recording axis flips) and sets the origin field to 0. In future, we’ll raise an error rather than try and estimate the affine from version 1 fields

aff_to_hdr

nibabel.trackvis.aff_to_hdr(affine, trk_hdr, pos_vox=None, set_order=None)

Set affine affine into trackvis header trk_hdr

Affine is mapping from voxel space to Nifti RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior. Sets affine if possible, and voxel sizes, and voxel axis ordering.

Parameters:

affine : (4,4) array-like

Affine voxel to mm transformation

trk_hdr : mapping

Mapping implementing __setitem__

pos_vos : None or bool

If None, currently defaults to False - this will change in future versions of nibabel. If False, allow negative voxel sizes in header to record axis flips. Negative voxels cause problems for trackvis (the application). If True, enforce positive voxel sizes.

set_order : None or bool

If None, currently defaults to False - this will change in future versions of nibabel. If False, do not set voxel_order field in trk_hdr. If True, calculcate voxel_order from affine and set into trk_hdr.

Returns:

None :

Notes

version 2 of the trackvis header has a dedicated field for the nifti RAS affine. In theory trackvis 1 has enough information to store an affine, with the fields ‘origin’, ‘voxel_size’ and ‘image_orientation_patient’. Unfortunately, to be able to store any affine, we’d need to be able to set negative voxel sizes, to encode axis flips. This is because ‘image_orientation_patient’ is only two columns of the 3x3 rotation matrix, and we need to know the number of flips to reconstruct the third column reliably. It turns out that negative flips upset trackvis (the application). The application also ignores the origin field, and may not use the ‘image_orientation_patient’ field.

empty_header

nibabel.trackvis.empty_header(endianness=None, version=2)

Empty trackvis header

Parameters:

endianness : {‘<’,’>’}, optional

Endianness of empty header to return. Default is native endian.

version : int, optional

Header version. 1 or 2. Default is 2

Returns:

hdr : structured array

structured array containing empty trackvis header

Notes

The trackvis header can store enough information to give an affine mapping between voxel and world space. Often this information is missing. We make no attempt to fill it with sensible defaults on the basis that, if the information is missing, it is better to be explicit.

Examples

>>> hdr = empty_header()
>>> print(hdr['version'])
2
>>> np.asscalar(hdr['id_string']) == b'TRACK'
True
>>> endian_codes[hdr['version'].dtype.byteorder] == native_code
True
>>> hdr = empty_header(swapped_code)
>>> endian_codes[hdr['version'].dtype.byteorder] == swapped_code
True
>>> hdr = empty_header(version=1)
>>> print(hdr['version'])
1

read

nibabel.trackvis.read(fileobj, as_generator=False, points_space=None)

Read trackvis file, return streamlines, header

Parameters:

fileobj : string or file-like object

If string, a filename; otherwise an open file-like object pointing to trackvis file (and ready to read from the beginning of the trackvis header data)

as_generator : bool, optional

Whether to return tracks as sequence (False, default) or as a generator (True).

points_space : {None, ‘voxel’, ‘rasmm’}, optional

The coordinates in which you want the points in the output streamlines expressed. If None, then return the points exactly as they are stored in the trackvis file. The points will probably be in trackviz voxmm space - see Notes for write function. If ‘voxel’, we convert the points to voxel space simply by dividing by the recorded voxel size. If ‘rasmm’ we’ll convert the points to RAS mm space (real space). For ‘rasmm’ we check if the affine is set and matches the voxel sizes and voxel order.

Returns:

streamlines : sequence or generator

Returns sequence if as_generator is False, generator if True. Value is sequence or generator of 3 element sequences with elements:

  1. points : ndarray shape (N,3) where N is the number of points
  2. scalars : None or ndarray shape (N, M) where M is the number of scalars per point
  3. properties : None or ndarray shape (P,) where P is the number of properties

hdr : structured array

structured array with trackvis header fields

Notes

The endianness of the input data can be deduced from the endianness of the returned hdr or streamlines

Points are in trackvis voxel mm. Each track has N points, each with 3 coordinates, x, y, z, where x is the floating point voxel coordinate along the first image axis, multiplied by the voxel size for that axis.

write

nibabel.trackvis.write(fileobj, streamlines, hdr_mapping=None, endianness=None, points_space=None)

Write header and streamlines to trackvis file fileobj

The parameters from the streamlines override conflicting parameters in the hdr_mapping information. In particular, the number of streamlines, the number of scalars, and the number of properties are written according to streamlines rather than hdr_mapping.

Parameters:

fileobj : filename or file-like

If filename, open file as ‘wb’, otherwise fileobj should be an open file-like object, with a write method.

streamlines : iterable

iterable returning 3 element sequences with elements:

  1. points : ndarray shape (N,3) where N is the number of points
  2. scalars : None or ndarray shape (N, M) where M is the number of scalars per point
  3. properties : None or ndarray shape (P,) where P is the number of properties

If streamlines has a len (for example, it is a list or a tuple), then we can write the number of streamlines into the header. Otherwise we write 0 for the number of streamlines (a valid trackvis header) and write streamlines into the file until the iterable is exhausted. M - the number of scalars - has to be the same for each streamline in streamlines. Similarly for P. See points_space and Notes for more detail on the coordinate system for points above.

hdr_mapping : None, ndarray or mapping, optional

Information for filling header fields. Can be something dict-like (implementing items) or a structured numpy array

endianness : {None, ‘<’, ‘>’}, optional

Endianness of file to be written. ‘<’ is little-endian, ‘>’ is big-endian. None (the default) is to use the endianness of the streamlines data.

points_space : {None, ‘voxel’, ‘rasmm’}, optional

The coordinates in which the points in the input streamlines are expressed. If None, then assume the points are as you want them (probably trackviz voxmm space - see Notes). If ‘voxel’, the points are in voxel space, and we will transform them to trackviz voxmm space. If ‘rasmm’ the points are in RAS mm space (real space). We transform them to trackvis voxmm space. If ‘voxel’ or ‘rasmm’ we insist that the voxel sizes and ordering are set to non-default values. If ‘rasmm’ we also check if the affine is set and matches the voxel sizes

Returns:

None :

Notes

Trackvis (the application) expects the points in the streamlines be in what we call trackviz voxmm coordinates. If we have a point (x, y, z) in voxmm coordinates, and voxel_size has the voxel sizes for each of the 3 dimensions, then x, y, z refer to mm in voxel space. Thus if i, j, k is a point in voxel coordinates, then x = i * voxel_size[0]; y = j * voxel_size[1]; z = k * voxel_size[2]. The spatial direction of x, y and z are defined with the “voxel_order” field. For example, if the original image had RAS voxel ordering then “voxel_order” would be “RAS”. RAS here refers to the spatial direction of the voxel axes: “R” means that moving along first voxel axis moves from left to right in space, “A” -> second axis goes from posterior to anterior, “S” -> inferior to superior. If “voxel_order” is empty we assume “LPS”.

This information comes from some helpful replies on the trackviz forum about interpreting point coordiantes

Examples

>>> from io import BytesIO
>>> file_obj = BytesIO()
>>> pts0 = np.random.uniform(size=(10,3))
>>> pts1 = np.random.uniform(size=(10,3))
>>> streamlines = ([(pts0, None, None), (pts1, None, None)])
>>> write(file_obj, streamlines)
>>> _ = file_obj.seek(0) # returns 0 in python 3
>>> streams, hdr = read(file_obj)
>>> len(streams)
2

If there are too many streamlines to fit in memory, you can pass an iterable thing instead of a list

>>> file_obj = BytesIO()
>>> def gen():
...     yield (pts0, None, None)
...     yield (pts0, None, None)
>>> write(file_obj, gen())
>>> _ = file_obj.seek(0)
>>> streams, hdr = read(file_obj)
>>> len(streams)
2