fsleyes.displaycontext.niftiopts
This module defines the NiftiOpts
class.
An important note on coordinate systems
FSLeyes displays all overlays in a single coordinate system, referred
throughout as the display coordinate system. However, Nifti
overlays can potentially be transformed into the display coordinate system
in one of several ways:
voxels
(a.k.a.
id
) The image data voxel coordinates map to the display coordinates.scaled voxels
(a.k.a.
pixdim
) The image data voxel coordinates are scaled by thepixdim
values stored in the NIFTI header. The origin is fixed at the centre of voxel(0, 0, 0)
.radioloigcal scaled voxels
(a.k.a.
pixdim-flip
) The image data voxel coordinates are scaled by thepixdim
values stored in the NIFTI header and, if the image appears to be stored in neurological order, the X (left-right) axis is inverted. The origin is fixed at the centre of voxel(0, 0, 0)
(or(X-1, 0, 0)
for inverted images).world
(a.k.a.
affine
) The image data voxel coordinates are transformed by the transformation matrix stored in the NIFTI header - see theNifti
class for more details.reference
(a.k.a.
reference
) The image data voxel coordinates are transformed into thepixdim-flip
coordinate system of another, reference, NIFTI image. The reference overlay is specified by theDisplayContext.displaySpace
attribute.
The NiftiOpts.transform
property controls how the image data is
transformed into the display coordinate system. It allows any of the above
spaces to be specified (as id
, pixdim
, pixdim-flip
, affine`
,
or reference
respectively).
Pixdim flip
The pixdim-flip
transform is the coordinate system used internally by many
of the FSL tools. For instance, this is the coordinate system used by
FSLView, by flirt
, and in the VTK sub-cortical segmentation model files
output by first
.
Furthermore, the vectors in eigenvector images images output by dtifit
are
oriented according to this space, so if the input data is in neurological
orientation, these vectors need to be inverted along the x axis.
https://fsl.fmrib.ox.ac.uk/fsl/docs/#/registration/flirt/faq?id=what-is-the-format-of-the-matrix-used-by-flirt-and-how-does-it-relate-to-the-transformation-parameters
What is a voxel?
Regardless of the space in which the Nifti
is displayed , the
voxel-to-display space transformation (and in general, all of FSLeyes) assumes
that integer voxel coordinates correspond to the centre of the voxel in the
display coordinate system. In other words, a voxel at location:
[x, y, z]
is assumed to occupy the space that corresponds to:
[x-0.5 - x+0.5, y-0.5 - y+0.5, z-0.5 - z+0.5]
For example, if the NiftiOpts.transform
property is set to id
, the
voxel:
[2, 3, 4]
is drawn such that it occupies the space:
[1.5 - 2.5, 2.5 - 3.5, 3.5 - 4.5]
This convention is in line with the convention defined by the NIFTI
specification: it assumes that the voxel coordinates [x, y, z]
correspond
to the centre of a voxel.
- class fsleyes.displaycontext.niftiopts.NiftiOpts(*args, **kwargs)[source]
Bases:
DisplayOpts
The
NiftiOpts
class describes how aNifti
overlay should be displayed.NiftiOpts
is the base class for a number ofDisplayOpts
sub-classes - it contains display options which are common to all overlay types that represent a NIFTI image.- volume
If the
Image
has more than 3 dimensions, the current volume to display. The volume dimension is controlled by thevolumeDim
property.
- volumeDim
For images with more than three dimensions, this property controls the dimension that the
volume
property indexes into. When thevolumeDim
changes, thevolume
for the previousvolumeDim
is fixed at its last value, and used for subsequent lookups.
- transform
This property defines how the overlay should be transformd into the display coordinate system. See the note on coordinate systems for important information regarding this property.
- displayXform
A custom transformation matrix which is concatenated on to the voxel -> world transformation of the
Nifti
overlay.This transform is intended for temporary changes to the overlay display (when
DisplayContext.displaySpace
== 'world'
) - changes to it will not result in the :DisplayContext.bounds
being updated.If you change the
displayXform
, make sure to change it back to an identity matrix when you are done.
- enableOverrideDataRange
By default, the
Image.dataRange
property is used to set display and clipping ranges. However, if this property isTrue
, theoverrideDataRange
is used instead.- ..note:: The point of this property is to make it easier to display images
with a very large data range driven by outliers. On platforms which do not support floating point textures, these images are impossible to display unless they are normalised according to a smaller data range. See the
Texture3D.__determineTextureType()
method for some more details.
- overrideDataRange
Data range used in place of the
Image.dataRange
if theenableOverrideDataRange
property isTrue
.
- __init__(*args, **kwargs)[source]
Create a
NiftiOpts
instance.All arguments are passed through to the
DisplayOpts
constructor.
- destroy()[source]
Calls the
DisplayOpts.destroy()
method.
- __toggleSiblingListeners(enable=True)
Enables/disables the
volumeDim
listeners of siblingNiftiOpts
instances. This is used by the__volumeDimChanged()
method to avoid nastiness.
- __volumeDimChanged(*a)
Called when the
volumeDim
changes. Saves the value ofvolume
for the lastvolumeDim
, and restores the previous value ofvolume
for the newvolumeDim
.
- __overlayTransformChanged(*a)
Called when the
Nifti
overlay sends a notification on the'transform'
topic, indicating that its voxel->world transformation matrix has been updated.
- __displaySpaceTransformChanged(*a)
Called when the
DisplayContext.displaySpace
is aNifti
overlay, and itsNifti.voxToWorldMat
changes. Updates the transformation matrices for this image.
- __transformChanged(*a)
Called when the
transform
property changes.Calculates the min/max values of a 3D bounding box, in the display coordinate system, which is big enough to contain the image. Sets the
DisplayOpts.bounds
property accordingly.
- __displaySpaceChanged(*a, **kwa)
Called when the
DisplayContext.displaySpace
property changes. Re-generates transformation matrices, and re-calculates the displaybounds
(via calls to__setupTransforms()
and__transformChanged()
).
- __displayXformChanged(*a)
Called when the
displayXform
property changes. Updates the transformation matrices andbounds
accordingly.Critically, when the
displayXform
property changes, theDisplayContext
is not notified. This is because thedisplayXform
is intended for temporary changes.
- __setupTransforms()
Calculates transformation matrices between all of the possible spaces in which the overlay may be displayed.
These matrices are accessible via the
getTransform()
method.
- classmethod getVolumeProps()[source]
Overrides
DisplayOpts.getVolumeProps()
. Returns a list of property names which control the displayed volume/timepoint.
- __annotations__ = {}
- __module__ = 'fsleyes.displaycontext.niftiopts'
- getTransform(from_, to)[source]
Return a matrix which may be used to transform coordinates from
from_
toto
. Valid values forfrom_
andto
are:id
Voxel coordinates
voxel
Equivalent to
id
.pixdim
Voxel coordinates, scaled by voxel dimensions
pixdim-flip
Voxel coordinates, scaled by voxel dimensions, and with the X axis flipped if the affine matrix has a positivie determinant. If the affine matrix does not have a positive determinant, this is equivalent to
pixdim
.pixflip
Equivalent to
pixdim-flip
.affine
World coordinates, as defined by the NIFTI
qform
/sform
. SeeImage.voxToWorldMat
.world
Equivalent to
affine
.reference
pixdim-flip
coordinates of the reference image specified by theDisplayContext.displaySpace
attribute. If thedisplaySpace
is set to'world'
, this is equivalent toaffine
.ref
Equivalent to
reference
.display
Equivalent to the current value of
transform
.texture
Voxel coordinates scaled to lie between 0.0 and 1.0, suitable for looking up voxel values when stored as an OpenGL texture.
- roundVoxels(voxels, daxes=None, roundOther=False)[source]
Round the given voxel coordinates to integers. This is a surprisingly complicated operation.
FSLeyes and the NIFTI standard map integer voxel coordinates to the voxel centre. For example, a voxel [3, 4, 5] fills the space:
[2.5-3.5, 3.5-4.5, 4.5-5.5].
So all we need to do is round to the nearest integer. But there are a few problems with breaking ties when rounding…
The numpy.round function breaks ties (e.g. 7.5) by rounding to the nearest even integer, which can cause funky behaviour. So instead of using numpy.round, we take floor(x+0.5), to force consistent behaviour (i.e. always rounding central values up).
The next problem is that we have to round the voxel coordaintes carefully, depending on the orientation of the voxel axis w.r.t. the display axis. We want to round in the same direction in the display coordinate system, regardless of the voxel orientation. So we need to check the orientation of the voxel axis, and round down or up accordingly.
This is to handle scenarios where we have two anatomically aligned images, but with opposing storage orders (e.g. one stored neurologically, and one stored radiologically). If we have such images, and the display location is on a voxel boundary, we want the voxel coordinates for one image to be rounded in the same anatomical direction (i.e. the same direction in the display coordinate system). Otherwise the same display location will map to mis-aligned voxels in the two images, because the voxel coordinate rounding will move in anatomically opposing directions.
This method also prevents coordinates that are close to 0 from being set to -1, and coordinates that are close to the axis size from being set to (size + 1). In other words, voxel coordinates which are on the low or high boundaries will be rounded so as to be valid voxel coordinates.
- Parameters:
voxels – A
(N, 3)
numpy
array containing the voxel coordinates to be rounded.daxes – Display coordinate system axes along which to round the coordinates (defaults to all axes).
roundOther – If
True
, any voxel axes which are not indaxes
will still be rounded, but not with an orientation-specific rounding convention.
- Returns:
The
voxels
, rounded appropriately.
- transformCoords(coords, from_, to_, vround=False, vector=False, pre=None, post=None)[source]
Transforms the given coordinates from
from_
toto_
.The
from_
andto_
parameters must be those accepted by thegetTransform()
method.- Parameters:
coords – Coordinates to transform
from – Space to transform from
to – Space to transform to
vround – If
True
, andto_ in ('voxel', 'id)
, the transformed coordinates are rounded to the nearest integer.vector – Defaults to
False
. IfTrue
, the coordinates are treated as vectors.pre – Transformation to apply before the
from_
-to-to
transformation.post – Transformation to apply after the
from_
-to-to
transformation.
- getVoxel(xyz=None, clip=True, vround=True)[source]
Calculates and returns the voxel coordinates corresponding to the given location (assumed to be in the display coordinate system) for the
Nifti
associated with thisNiftiOpts
instance..- Parameters:
xyz – Display space location to convert to voxels. If not provided, the current
DisplayContext.location
is used.clip – If
False
, and the transformed coordinates are out of the voxel coordinate bounds, the coordinates returned anyway. Defaults toTrue
.vround – If
True
, the returned voxel coordinates are rounded to the nearest integer. Otherwise they may be fractional.
- Returns:
None
if the location is outside of the image bounds, unlessclip=False
.
- setIndex(indices)[source]
Sets the indexes of all non-spatial dimensions. The
volume
property is also updated.