diff --git a/fsl/data/image.py b/fsl/data/image.py index 95aa3875dfbd547323336cd017700378aa75fd6a..d4edf9690ddf30a10c8ac22d673814c77a35d360 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -34,6 +34,7 @@ and file names: import os import os.path as op +import itertools as it import string import logging import tempfile @@ -408,6 +409,54 @@ class Nifti(notifier.Notifier, meta.Meta): return affines, isneuro + @staticmethod + def identifyAffine(image, xform, from_=None, to=None): + """Attempt to identify the source or destination space for the given + affine. + + ``xform`` is assumed to be an affine transformation which can be used + to transform coordinates between two coordinate systems associated with + ``image``. + + If one of ``from_`` or ``to`` is provided, the other will be derived. + If neither are provided, both will be derived. See the + :meth:`.Nifti.getAffine` method for details on the valild values that + ``from_`` and ``to`` may take. + + :arg image: :class:`.Nifti` instance associated with the affine. + + :arg xform: ``(4, 4)`` ``numpy`` array encoding an affine + transformation + + :arg from_: Label specifying the coordinate system which ``xform`` + takes as input + + :arg to: Label specifying the coordinate system which ``xform`` + produces as output + + :returns: A tuple containing: + - A label for the ``from_`` coordinate system + - A label for the ``to`` coordinate system + """ + + if (from_ is not None) and (to is not None): + return from_, to + + if from_ is not None: froms = [from_] + else: froms = ['voxel', 'fsl', 'world'] + if to is not None: tos = [to] + else: tos = ['voxel', 'fsl', 'world'] + + for from_, to in it.product(froms, tos): + + candidate = image.getAffine(from_, to) + + if np.all(np.isclose(candidate, xform)): + return from_, to + + raise ValueError('Could not identify affine') + + def strval(self, key): """Returns the specified NIFTI header field, converted to a python string, correctly null-terminated, and with non-printable characters diff --git a/fsl/transform/affine.py b/fsl/transform/affine.py index 5aaa66f35abe812c061c10e0de92c48fc996fac8..e0364bf94030c76d6df99a5222ce6439bed8df38 100644 --- a/fsl/transform/affine.py +++ b/fsl/transform/affine.py @@ -21,7 +21,6 @@ transformations. The following functions are available: axisAnglesToRotMat axisBounds rmsdev - identify And a few more functions are provided for working with vectors: @@ -34,9 +33,9 @@ And a few more functions are provided for working with vectors: """ +import collections.abc as abc import numpy as np import numpy.linalg as linalg -import collections.abc as abc def invert(x): @@ -583,57 +582,3 @@ def rmsdev(T1, T2, R=None, xc=None): erms = np.sqrt(erms) return erms - - -def identify(image, xform, from_=None, to=None): - """Attempt to identify the source or destination space for the given - affine. - - ``xform`` is assumed to be an affine transformation which can be used - to transform coordinates between two coordinate systems associated with - ``image``. - - One of ``from_`` or ``to`` must be provided. Whichever is not provided - will be derived. See the :meth:`.Nifti.getAffine` method for details on - the valild values that ``from_`` and ``to`` may take. - - :arg image: :class:`.Nifti` instance associated with the affine. - - :arg xform: ``(4, 4)`` ``numpy`` array encoding an affine transformation - - :arg from_: Label specifying the coordinate system which ``xform`` - takes as input - - :arg to: Label specifying the coordinate system which ``xform`` - produces as output - - :returns: A tuple containing: - - A label for the ``from_`` coordinate system - - A label for the ``to`` coordinate system - """ - - if (from_ is None) and (to is None): - raise ValueError('One of from_ or to must be provided') - - if (from_ is not None) and (to is not None): - return from_, to - - if from_ is None: - voxel = image.getAffine('voxel', to) - fsl = image.getAffine('fsl', to) - world = image.getAffine('world', to) - - if np.all(np.isclose(voxel, xform)): return 'voxel', to - if np.all(np.isclose(fsl, xform)): return 'fsl', to - if np.all(np.isclose(world, xform)): return 'world', to - - if to is None: - voxel = image.getAffine(from_, 'voxel') - fsl = image.getAffine(from_, 'fsl') - world = image.getAffine(from_, 'world') - - if np.all(np.isclose(voxel, xform)): return 'voxel', to - if np.all(np.isclose(fsl, xform)): return 'fsl', to - if np.all(np.isclose(world, xform)): return 'world', to - - raise ValueError('Could not identify affine') diff --git a/fsl/transform/x5.py b/fsl/transform/x5.py index 5e3162f4529c42e39eaffd922769abc232e5f934..1d29a5777663d2b9c6f88cfac2648a7266636e8f 100644 --- a/fsl/transform/x5.py +++ b/fsl/transform/x5.py @@ -335,9 +335,10 @@ import numpy as np import nibabel as nib import h5py -import fsl.version as version -from . import affine -from . import nonlinear +import fsl.version as version +import fsl.data.image as fslimage +from . import affine +from . import nonlinear X5_FORMAT = 'X5' @@ -593,9 +594,11 @@ def _readNonLinearCommon(group): try: if pre is not None: - refSpace = affine.identify(ref, pre, from_='world')[1] + refSpace = fslimage.Nifti.identifyAffine( + ref, pre, from_='world')[1] if post is not None: - srcSpace = affine.identify(src, post, to='world')[ 0] + srcSpace = fslimage.Nifti.identifyAffine( + src, post, to='world')[ 0] except ValueError: raise X5Error('Invalid pre/post affine')