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 |
Bases: object
Convenience class to encapsulate trackvis file information
Parameters: | streamlines : sequence
mapping : None or mapping
endianness : {None, ‘<’, ‘>’}
filename : None or str, optional
points_space : {None, ‘voxel’, ‘rasmm’}, optional
affine : None or (4,4) ndarray, optional
|
---|
Get affine from header in object
Returns: | aff : (4,4) ndarray
atleast_v2 : None or bool, optional
|
---|
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 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
pos_vos : None or bool, optional
set_order : None or bool, optional
|
---|---|
Returns: | 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
atleast_v2 : None or bool
|
---|---|
Returns: | aff : (4,4) array
|
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
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
trk_hdr : mapping
pos_vos : None or bool
set_order : None or bool
|
---|---|
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 trackvis header
Parameters: | endianness : {‘<’,’>’}, optional
version : int, optional
|
---|---|
Returns: | hdr : structured array
|
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 trackvis file, return streamlines, header
Parameters: | fileobj : string or file-like object
as_generator : bool, optional
points_space : {None, ‘voxel’, ‘rasmm’}, optional
|
---|---|
Returns: | streamlines : sequence or generator
hdr : structured array
|
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 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
streamlines : iterable
hdr_mapping : None, ndarray or mapping, optional
endianness : {None, ‘<’, ‘>’}, optional
points_space : {None, ‘voxel’, ‘rasmm’}, optional
|
---|---|
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