Skip to content

Support for motion parameters produced by AFNI (FD) #1840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions nipype/algorithms/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
from ..interfaces.base import (traits, TraitedSpec, BaseInterface,
BaseInterfaceInputSpec, File, isdefined,
InputMultiPath)
from nipype.utils import NUMPY_MMAP
from ..utils import NUMPY_MMAP
from ..utils.misc import normalize_mc_params

IFLOG = logging.getLogger('interface')

Expand Down Expand Up @@ -195,7 +196,10 @@ def _list_outputs(self):


class FramewiseDisplacementInputSpec(BaseInterfaceInputSpec):
in_plots = File(exists=True, mandatory=True, desc='motion parameters as written by FSL MCFLIRT')
in_file = File(exists=True, mandatory=True, desc='motion parameters')
parameter_source = traits.Enum("FSL", "AFNI", "SPM", "FSFAST",
desc="Source of movement parameters",
mandatory=True)
radius = traits.Float(50, usedefault=True,
desc='radius in mm to calculate angular FDs, 50mm is the '
'default since it is used in Power et al. 2012')
Expand Down Expand Up @@ -249,9 +253,12 @@ class FramewiseDisplacement(BaseInterface):
}]

def _run_interface(self, runtime):
mpars = np.loadtxt(self.inputs.in_plots) # mpars is N_t x 6
diff = mpars[:-1, :] - mpars[1:, :]
diff[:, :3] *= self.inputs.radius
mpars = np.loadtxt(self.inputs.in_file) # mpars is N_t x 6
mpars = np.apply_along_axis(func1d=normalize_mc_params,
axis=1, arr=mpars,
source=self.inputs.parameter_source)
diff = mpars[:-1, :6] - mpars[1:, :6]
diff[:, 3:6] *= self.inputs.radius
fd_res = np.abs(diff).sum(axis=1)

self._results = {
Expand Down
9 changes: 3 additions & 6 deletions nipype/algorithms/rapidart.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
OutputMultiPath, TraitedSpec, File,
BaseInterfaceInputSpec, isdefined)
from ..utils.filemanip import filename_to_list, save_json, split_filename
from ..utils.misc import find_indices
from ..utils.misc import find_indices, normalize_mc_params
from .. import logging, config
iflogger = logging.getLogger('interface')

Expand All @@ -46,15 +46,12 @@ def _get_affine_matrix(params, source):
source : the package that generated the parameters
supports SPM, AFNI, FSFAST, FSL, NIPY
"""
if source == 'FSL':
params = params[[3, 4, 5, 0, 1, 2]]
elif source in ('AFNI', 'FSFAST'):
params = params[np.asarray([4, 5, 3, 1, 2, 0]) + (len(params) > 6)]
params[3:] = params[3:] * np.pi / 180.
if source == 'NIPY':
# nipy does not store typical euler angles, use nipy to convert
from nipy.algorithms.registration import to_matrix44
return to_matrix44(params)

params = normalize_mc_params(params, source)
# process for FSL, SPM, AFNI and FSFAST
rotfunc = lambda x: np.array([[np.cos(x), np.sin(x)],
[-np.sin(x), np.cos(x)]])
Expand Down
2 changes: 1 addition & 1 deletion nipype/algorithms/tests/test_auto_FramewiseDisplacement.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_FramewiseDisplacement_inputs():
ignore_exception=dict(nohash=True,
usedefault=True,
),
in_plots=dict(mandatory=True,
in_file=dict(mandatory=True,
),
normalize=dict(usedefault=True,
),
Expand Down
5 changes: 3 additions & 2 deletions nipype/algorithms/tests/test_confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
def test_fd(tmpdir):
tempdir = str(tmpdir)
ground_truth = np.loadtxt(example_data('fsl_motion_outliers_fd.txt'))
fdisplacement = FramewiseDisplacement(in_plots=example_data('fsl_mcflirt_movpar.txt'),
out_file=tempdir + '/fd.txt')
fdisplacement = FramewiseDisplacement(in_file=example_data('fsl_mcflirt_movpar.txt'),
out_file=tempdir + '/fd.txt',
parameter_source="FSL")
res = fdisplacement.run()

with open(res.outputs.out_file) as all_lines:
Expand Down
12 changes: 12 additions & 0 deletions nipype/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,15 @@ def unflatten(in_list, prev_structure):
for item in prev_structure:
out.append(unflatten(in_list, item))
return out


def normalize_mc_params(params, source):
"""
Normalize a single row of motion parameters to the SPM format.
"""
if source == 'FSL':
params = params[[3, 4, 5, 0, 1, 2]]
elif source in ('AFNI', 'FSFAST'):
params = params[np.asarray([4, 5, 3, 1, 2, 0]) + (len(params) > 6)]
params[3:] = params[3:] * np.pi / 180.
return params