Skip to content
Snippets Groups Projects
Commit 4bbd521a authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

RF,BF: Fixes/adjustments to nonlinear module, and in particular to

convertDisplacementSpace
parent 3a607236
No related branches found
No related tags found
No related merge requests found
...@@ -26,10 +26,13 @@ class NonLinearTransform(fslimage.Image): ...@@ -26,10 +26,13 @@ class NonLinearTransform(fslimage.Image):
some mapping between a source image coordinate system and a reference image some mapping between a source image coordinate system and a reference image
coordinate system. coordinate system.
In FSL, non-linear transformations are defined in the same space as the In FSL, non-linear transformations are defined in the same space as the
reference image. At a given location in the reference image space, the reference image. At a given location in the reference image space, the
non-linear mapping at that location can be used to calculate the non-linear mapping at that location can be used to calculate the
corresponding location in the source image space. corresponding location in the source image space. Therefore, these
non-linear transformation effectively encode a transformation *from* the
reference image *to* the source image.
""" """
...@@ -46,7 +49,7 @@ class NonLinearTransform(fslimage.Image): ...@@ -46,7 +49,7 @@ class NonLinearTransform(fslimage.Image):
or a :mod:`numpy` array, or a :mod:`nibabel` image or a :mod:`numpy` array, or a :mod:`nibabel` image
object. object.
:arg src: :class:`.Nifti` representing the sourceimage :arg src: :class:`.Nifti` representing the source image.
:arg ref: :class:`.Nifti` representing the reference image. :arg ref: :class:`.Nifti` representing the reference image.
If not provided, it is assumed that this If not provided, it is assumed that this
...@@ -66,11 +69,6 @@ class NonLinearTransform(fslimage.Image): ...@@ -66,11 +69,6 @@ class NonLinearTransform(fslimage.Image):
if srcSpace is None: srcSpace = 'fsl' if srcSpace is None: srcSpace = 'fsl'
if refSpace is None: refSpace = 'fsl' if refSpace is None: refSpace = 'fsl'
if not (isinstance(src, (fslimage.Nifti, type(None))) and
isinstance(ref, fslimage.Nifti)):
raise ValueError('Invalid source/reference: {} -> {}'.format(
src, ref))
if srcSpace not in ('fsl', 'voxel', 'world') or \ if srcSpace not in ('fsl', 'voxel', 'world') or \
refSpace not in ('fsl', 'voxel', 'world'): refSpace not in ('fsl', 'voxel', 'world'):
raise ValueError('Invalid source/reference space: {} -> {}'.format( raise ValueError('Invalid source/reference space: {} -> {}'.format(
...@@ -78,6 +76,12 @@ class NonLinearTransform(fslimage.Image): ...@@ -78,6 +76,12 @@ class NonLinearTransform(fslimage.Image):
fslimage.Image.__init__(self, image, **kwargs) fslimage.Image.__init__(self, image, **kwargs)
# Displacement fields must be
# defined in the same space
# as the reference image
if not self.sameSpace(ref):
raise ValueError('Invalid reference image: {}'.format(ref))
self.__src = fslimage.Nifti(src.header.copy()) self.__src = fslimage.Nifti(src.header.copy())
self.__ref = fslimage.Nifti(ref.header.copy()) self.__ref = fslimage.Nifti(ref.header.copy())
self.__srcSpace = srcSpace self.__srcSpace = srcSpace
...@@ -172,7 +176,8 @@ class DisplacementField(NonLinearTransform): ...@@ -172,7 +176,8 @@ class DisplacementField(NonLinearTransform):
def transform(self, coords, from_=None, to=None): def transform(self, coords, from_=None, to=None):
"""Transform the given XYZ coordinates from the reference to the source. """Transform the given XYZ coordinates from the reference image space
to the source image space.
:arg coords: A sequence of XYZ coordinates, or ``numpy`` array of shape :arg coords: A sequence of XYZ coordinates, or ``numpy`` array of shape
``(n, 3)`` containing ``n`` sets of coordinates in the ``(n, 3)`` containing ``n`` sets of coordinates in the
...@@ -192,22 +197,21 @@ class DisplacementField(NonLinearTransform): ...@@ -192,22 +197,21 @@ class DisplacementField(NonLinearTransform):
# same reference image space as the # same reference image space as the
# displacements # displacements
if from_ != self.refSpace: if from_ != self.refSpace:
coords = affine.transform( xform = self.ref.getAffine(from_, self.refSpace)
coords, self.ref.getAffine(from_, self.refSpace)) coords = affine.transform(coords, xform)
# We also need to make sure that the # We also need to make sure that the
# coordinates are in voxels, so we # coordinates are in voxels, so we
# can look up the displacements # can look up the displacements
if self.refSpace != 'voxel': if self.refSpace != 'voxel':
voxels = affine.transform( xform = self.ref.getAffine(self.refSpace, 'voxel')
coords, self.ref.getAffine(self.refSpace, 'voxel')) voxels = affine.transform(coords, xform)
else: else:
voxels = coords voxels = coords
voxels = np.round(voxels).astype(np.int)
# Mask out the coordinates # Mask out the coordinates
# that are out of bounds # that are out of bounds
voxels = np.round(voxels).astype(np.int)
voxmask = (voxels >= [0, 0, 0]) & (voxels < self.shape[:3]) voxmask = (voxels >= [0, 0, 0]) & (voxels < self.shape[:3])
voxmask = voxmask.all(axis=1) voxmask = voxmask.all(axis=1)
voxels = voxels[voxmask] voxels = voxels[voxmask]
...@@ -221,8 +225,8 @@ class DisplacementField(NonLinearTransform): ...@@ -221,8 +225,8 @@ class DisplacementField(NonLinearTransform):
# are in the requested # are in the requested
# source image space # source image space
if to != self.srcSpace: if to != self.srcSpace:
disps = affine.transform( xform = self.src.getAffine(self.srcSpace, to)
disps, self.src.getAffine(self.srcSpace, to)) disps = affine.transform(disps, xform)
# Nans for input coordinates # Nans for input coordinates
# which were outside of the # which were outside of the
...@@ -276,12 +280,13 @@ def convertDisplacementType(field, dispType=None): ...@@ -276,12 +280,13 @@ def convertDisplacementType(field, dispType=None):
# we need the coordinates of every voxel # we need the coordinates of every voxel
# in the reference FSL coordinate system. # in the reference FSL coordinate system.
dx, dy, dz = field.shape[:3] dx, dy, dz = field.shape[:3]
v2fsl = field.getAffine('voxel', field.srcSpace) xform = field.getAffine('voxel', field.refSpace)
coords = np.meshgrid(np.arange(dx), coords = np.meshgrid(np.arange(dx),
np.arange(dy), np.arange(dy),
np.arange(dz), indexing='ij') np.arange(dz), indexing='ij')
coords = np.array(coords).transpose((1, 2, 3, 0)) coords = np.array(coords).transpose((1, 2, 3, 0))
coords = affine.transform(coords.reshape((-1, 3)), v2fsl) coords = affine.transform(coords.reshape((-1, 3)), xform)
coords = coords.reshape((dx, dy, dz, 3)) coords = coords.reshape((dx, dy, dz, 3))
# If converting from relative to absolute, # If converting from relative to absolute,
...@@ -299,47 +304,58 @@ def convertDisplacementSpace(field, from_, to): ...@@ -299,47 +304,58 @@ def convertDisplacementSpace(field, from_, to):
the ``from_`` and ``to`` arguments. the ``from_`` and ``to`` arguments.
:arg field: A :class:`DisplacementField` instance :arg field: A :class:`DisplacementField` instance
:arg from_: New source image coordinate system :arg from_: New reference image coordinate system
:arg to: New reference image coordinate system :arg to: New source image coordinate system
:returns: A new :class:`DisplacementField` which transforms between :returns: A new :class:`DisplacementField` which transforms between
the source ``from_`` coordinate system and the reference ``to`` the reference ``from_`` coordinate system and the source ``to``
coordinate system. coordinate system.
""" """
# Get the field in absolute # Get the field in absolute coordinates
# coordinates if necessary # if necessary - these are our source
# coordinates in the original "to" space.
fieldcoords = field.data fieldcoords = field.data
if field.relative: srccoords = convertDisplacementType(field) if field.relative: srccoords = convertDisplacementType(field)
else: srccoords = fieldcoords else: srccoords = fieldcoords
# Now transform those source
# coordinates from the original
# source space to the source
# space specified by "from_"
srcmat = field.src.getAffine(field.srcSpace, from_)
srccoords = srccoords.reshape((-1, 3)) srccoords = srccoords.reshape((-1, 3))
srccoords = affine.transform(srccoords, srcmat)
# Now transform those source coordinates
# from the original source space to the
# source space specified by "to"
if to != field.srcSpace:
srcmat = field.src.getAffine(field.srcSpace, to)
srccoords = affine.transform(srccoords, srcmat)
# If we have been asked to return # If we have been asked to return
# an absolute displacement, the # an absolute displacement, the
# reference "to" coordinate system # reference "from_" coordinate
# is irrelevant - we're done. # system is irrelevant - we're done.
if field.absolute: if field.absolute:
fieldcoords = srccoords fieldcoords = srccoords
# Otherwise our displacement field # Otherwise our displacement field
# will contain relative displacements # will contain relative displacements
# between the reference image "to" # between the reference image "from_"
# coordinate system and the source # coordinate system and the source
# image "from_" coordinate system. # image "to" coordinate system. We
# We need to re-calculate the relative # need to re-calculate the relative
# displacements between source "from_" # displacements between the new
# space and reference "to" space. # reference "from_" space and source
# "to" space.
else: else:
refmat = field.ref.getAffine(field.refSpace, to) refcoords = np.meshgrid(np.arange(field.shape[0]),
refcoords = fieldcoords.reshape((-1, 3)) np.arange(field.shape[1]),
refcoords = affine.transform(refcoords, refmat) np.arange(field.shape[2]), indexing='ij')
refcoords = np.array(refcoords)
refcoords = refcoords.transpose((1, 2, 3, 0)).reshape((-1, 3))
if from_ != 'voxel':
refmat = field.ref.getAffine('voxel', from_)
refcoords = affine.transform(refcoords, refmat)
fieldcoords = srccoords - refcoords fieldcoords = srccoords - refcoords
return DisplacementField( return DisplacementField(
...@@ -347,6 +363,6 @@ def convertDisplacementSpace(field, from_, to): ...@@ -347,6 +363,6 @@ def convertDisplacementSpace(field, from_, to):
header=field.header, header=field.header,
src=field.src, src=field.src,
ref=field.ref, ref=field.ref,
srcSpace=from_, srcSpace=to,
refSpace=to, refSpace=from_,
dispType=field.displacementType) dispType=field.displacementType)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment