diff --git a/nipype/algorithms/confounds.py b/nipype/algorithms/confounds.py index c6503c703a..d369fec9be 100644 --- a/nipype/algorithms/confounds.py +++ b/nipype/algorithms/confounds.py @@ -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') @@ -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') @@ -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 = { diff --git a/nipype/algorithms/rapidart.py b/nipype/algorithms/rapidart.py index 3b3295eab0..b8aca927b6 100644 --- a/nipype/algorithms/rapidart.py +++ b/nipype/algorithms/rapidart.py @@ -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') @@ -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)]]) diff --git a/nipype/algorithms/tests/test_auto_FramewiseDisplacement.py b/nipype/algorithms/tests/test_auto_FramewiseDisplacement.py index bd4afa89d0..c5eae5fb7d 100644 --- a/nipype/algorithms/tests/test_auto_FramewiseDisplacement.py +++ b/nipype/algorithms/tests/test_auto_FramewiseDisplacement.py @@ -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, ), diff --git a/nipype/algorithms/tests/test_confounds.py b/nipype/algorithms/tests/test_confounds.py index a1d6ec9557..f2fadf5cb0 100644 --- a/nipype/algorithms/tests/test_confounds.py +++ b/nipype/algorithms/tests/test_confounds.py @@ -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: diff --git a/nipype/utils/misc.py b/nipype/utils/misc.py index f01af7a02e..ea99daca36 100644 --- a/nipype/utils/misc.py +++ b/nipype/utils/misc.py @@ -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 \ No newline at end of file