diff --git a/nipype/algorithms/compcor.py b/nipype/algorithms/compcor.py deleted file mode 100644 index a2f2f434b3..0000000000 --- a/nipype/algorithms/compcor.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- -# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- -# vi: set ft=python sts=4 ts=4 sw=4 et: -''' -Miscellaneous algorithms - - Change directory to provide relative paths for doctests - >>> import os - >>> filepath = os.path.dirname(os.path.realpath(__file__)) - >>> datadir = os.path.realpath(os.path.join(filepath, '../testing/data')) - >>> os.chdir(datadir) - -''' -from ..interfaces.base import (BaseInterfaceInputSpec, TraitedSpec, - BaseInterface, traits, File) -from ..pipeline import engine as pe -from ..interfaces.utility import IdentityInterface -from .misc import regress_poly - -import nibabel as nb -import numpy as np -from scipy import linalg, stats -import os - -class CompCorInputSpec(BaseInterfaceInputSpec): - realigned_file = File(exists=True, mandatory=True, - desc='already realigned brain image (4D)') - mask_file = File(exists=True, mandatory=False, - desc='mask file that determines ROI (3D)') - components_file = File('components_file.txt', exists=False, - mandatory=False, usedefault=True, - desc='filename to store physiological components') - num_components = traits.Int(6, usedefault=True) # 6 for BOLD, 4 for ASL - use_regress_poly = traits.Bool(True, usedefault=True, - desc='use polynomial regression' - 'pre-component extraction') - regress_poly_degree = traits.Range(low=1, default=1, usedefault=True, - desc='the degree polynomial to use') - -class CompCorOutputSpec(TraitedSpec): - components_file = File(exists=True, - desc='text file containing the noise components') - -class CompCor(BaseInterface): - ''' - Interface with core CompCor computation, used in aCompCor and tCompCor - - Example - ------- - - >>> ccinterface = CompCor() - >>> ccinterface.inputs.realigned_file = 'functional.nii' - >>> ccinterface.inputs.mask_file = 'mask.nii' - >>> ccinterface.inputs.num_components = 1 - >>> ccinterface.inputs.use_regress_poly = True - >>> ccinterface.inputs.regress_poly_degree = 2 - ''' - input_spec = CompCorInputSpec - output_spec = CompCorOutputSpec - - def _run_interface(self, runtime): - imgseries = nb.load(self.inputs.realigned_file).get_data() - mask = nb.load(self.inputs.mask_file).get_data() - voxel_timecourses = imgseries[mask > 0] - # Zero-out any bad values - voxel_timecourses[np.isnan(np.sum(voxel_timecourses, axis=1)), :] = 0 - - # from paper: - # "The constant and linear trends of the columns in the matrix M were - # removed [prior to ...]" - if self.inputs.use_regress_poly: - voxel_timecourses = regress_poly(self.inputs.regress_poly_degree, - voxel_timecourses) - voxel_timecourses = voxel_timecourses - np.mean(voxel_timecourses, - axis=1)[:, np.newaxis] - - # "Voxel time series from the noise ROI (either anatomical or tSTD) were - # placed in a matrix M of size Nxm, with time along the row dimension - # and voxels along the column dimension." - M = voxel_timecourses.T - numvols = M.shape[0] - numvoxels = M.shape[1] - - # "[... were removed] prior to column-wise variance normalization." - M = M / self._compute_tSTD(M, 1.) - - # "The covariance matrix C = MMT was constructed and decomposed into its - # principal components using a singular value decomposition." - u, _, _ = linalg.svd(M, full_matrices=False) - components = u[:, :self.inputs.num_components] - components_file = os.path.join(os.getcwd(), self.inputs.components_file) - np.savetxt(components_file, components, fmt="%.10f") - return runtime - - def _list_outputs(self): - outputs = self._outputs().get() - outputs['components_file'] = os.path.abspath(self.inputs.components_file) - return outputs - - def _compute_tSTD(self, M, x): - stdM = np.std(M, axis=0) - # set bad values to x - stdM[stdM == 0] = x - stdM[np.isnan(stdM)] = x - return stdM - -class TCompCorInputSpec(CompCorInputSpec): - # and all the fields in CompCorInputSpec - percentile_threshold = traits.Range(low=0., high=1., value=.02, - exclude_low=True, exclude_high=True, - usedefault=True, desc='the percentile ' - 'used to select highest-variance ' - 'voxels, represented by a number ' - 'between 0 and 1, exclusive. By ' - 'default, this value is set to .02. ' - 'That is, the 2% of voxels ' - 'with the highest variance are used.') - -class TCompCor(CompCor): - ''' - Interface for tCompCor. Computes a ROI mask based on variance of voxels. - - Example - ------- - - >>> ccinterface = TCompCor() - >>> ccinterface.inputs.realigned_file = 'functional.nii' - >>> ccinterface.inputs.mask_file = 'mask.nii' - >>> ccinterface.inputs.num_components = 1 - >>> ccinterface.inputs.use_regress_poly = True - >>> ccinterface.inputs.regress_poly_degree = 2 - >>> ccinterface.inputs.percentile_threshold = .03 - ''' - - input_spec = TCompCorInputSpec - output_spec = CompCorOutputSpec - - def _run_interface(self, runtime): - imgseries = nb.load(self.inputs.realigned_file).get_data() - - # From the paper: - # "For each voxel time series, the temporal standard deviation is - # defined as the standard deviation of the time series after the removal - # of low-frequency nuisance terms (e.g., linear and quadratic drift)." - imgseries = regress_poly(2, imgseries) - imgseries = imgseries - np.mean(imgseries, axis=1)[:, np.newaxis] - - time_voxels = imgseries.T - num_voxels = np.prod(time_voxels.shape[1:]) - - # "To construct the tSTD noise ROI, we sorted the voxels by their - # temporal standard deviation ..." - tSTD = self._compute_tSTD(time_voxels, 0) - sortSTD = np.sort(tSTD, axis=None) # flattened sorted matrix - - # use percentile_threshold to pick voxels - threshold_index = int(num_voxels * (1. - self.inputs.percentile_threshold)) - threshold_std = sortSTD[threshold_index] - mask = tSTD >= threshold_std - mask = mask.astype(int) - - # save mask - mask_file = 'mask.nii' - nb.nifti1.save(nb.Nifti1Image(mask, np.eye(4)), mask_file) - self.inputs.mask_file = mask_file - - super(TCompCor, self)._run_interface(runtime) - return runtime - -ACompCor = CompCor diff --git a/nipype/algorithms/confounds.py b/nipype/algorithms/confounds.py index 227c9912af..b957e8d7fd 100644 --- a/nipype/algorithms/confounds.py +++ b/nipype/algorithms/confounds.py @@ -19,14 +19,16 @@ import nibabel as nb import numpy as np +from scipy import linalg +from scipy.special import legendre from .. import logging from ..external.due import due, Doi, BibTeX from ..interfaces.base import (traits, TraitedSpec, BaseInterface, - BaseInterfaceInputSpec, File, isdefined) + BaseInterfaceInputSpec, File, isdefined, + InputMultiPath) IFLOG = logging.getLogger('interface') - class ComputeDVARSInputSpec(BaseInterfaceInputSpec): in_file = File(exists=True, mandatory=True, desc='functional data, after HMC') in_mask = File(exists=True, mandatory=True, desc='a brain mask') @@ -276,6 +278,254 @@ def _run_interface(self, runtime): def _list_outputs(self): return self._results +class CompCorInputSpec(BaseInterfaceInputSpec): + realigned_file = File(exists=True, mandatory=True, + desc='already realigned brain image (4D)') + mask_file = File(exists=True, mandatory=False, + desc='mask file that determines ROI (3D)') + components_file = File('components_file.txt', exists=False, + mandatory=False, usedefault=True, + desc='filename to store physiological components') + num_components = traits.Int(6, usedefault=True) # 6 for BOLD, 4 for ASL + use_regress_poly = traits.Bool(True, usedefault=True, + desc='use polynomial regression' + 'pre-component extraction') + regress_poly_degree = traits.Range(low=1, default=1, usedefault=True, + desc='the degree polynomial to use') + +class CompCorOutputSpec(TraitedSpec): + components_file = File(exists=True, + desc='text file containing the noise components') + +class CompCor(BaseInterface): + ''' + Interface with core CompCor computation, used in aCompCor and tCompCor + + Example + ------- + + >>> ccinterface = CompCor() + >>> ccinterface.inputs.realigned_file = 'functional.nii' + >>> ccinterface.inputs.mask_file = 'mask.nii' + >>> ccinterface.inputs.num_components = 1 + >>> ccinterface.inputs.use_regress_poly = True + >>> ccinterface.inputs.regress_poly_degree = 2 + ''' + input_spec = CompCorInputSpec + output_spec = CompCorOutputSpec + + def _run_interface(self, runtime): + imgseries = nb.load(self.inputs.realigned_file).get_data() + mask = nb.load(self.inputs.mask_file).get_data() + voxel_timecourses = imgseries[mask > 0] + # Zero-out any bad values + voxel_timecourses[np.isnan(np.sum(voxel_timecourses, axis=1)), :] = 0 + + # from paper: + # "The constant and linear trends of the columns in the matrix M were + # removed [prior to ...]" + if self.inputs.use_regress_poly: + voxel_timecourses = regress_poly(self.inputs.regress_poly_degree, + voxel_timecourses) + voxel_timecourses = voxel_timecourses - np.mean(voxel_timecourses, + axis=1)[:, np.newaxis] + + # "Voxel time series from the noise ROI (either anatomical or tSTD) were + # placed in a matrix M of size Nxm, with time along the row dimension + # and voxels along the column dimension." + M = voxel_timecourses.T + numvols = M.shape[0] + numvoxels = M.shape[1] + + # "[... were removed] prior to column-wise variance normalization." + M = M / self._compute_tSTD(M, 1.) + + # "The covariance matrix C = MMT was constructed and decomposed into its + # principal components using a singular value decomposition." + u, _, _ = linalg.svd(M, full_matrices=False) + components = u[:, :self.inputs.num_components] + components_file = os.path.join(os.getcwd(), self.inputs.components_file) + np.savetxt(components_file, components, fmt=b"%.10f") + return runtime + + def _list_outputs(self): + outputs = self._outputs().get() + outputs['components_file'] = os.path.abspath(self.inputs.components_file) + return outputs + + def _compute_tSTD(self, M, x): + stdM = np.std(M, axis=0) + # set bad values to x + stdM[stdM == 0] = x + stdM[np.isnan(stdM)] = x + return stdM + +class TCompCorInputSpec(CompCorInputSpec): + # and all the fields in CompCorInputSpec + percentile_threshold = traits.Range(low=0., high=1., value=.02, + exclude_low=True, exclude_high=True, + usedefault=True, desc='the percentile ' + 'used to select highest-variance ' + 'voxels, represented by a number ' + 'between 0 and 1, exclusive. By ' + 'default, this value is set to .02. ' + 'That is, the 2% of voxels ' + 'with the highest variance are used.') + +class TCompCor(CompCor): + ''' + Interface for tCompCor. Computes a ROI mask based on variance of voxels. + + Example + ------- + + >>> ccinterface = TCompCor() + >>> ccinterface.inputs.realigned_file = 'functional.nii' + >>> ccinterface.inputs.mask_file = 'mask.nii' + >>> ccinterface.inputs.num_components = 1 + >>> ccinterface.inputs.use_regress_poly = True + >>> ccinterface.inputs.regress_poly_degree = 2 + >>> ccinterface.inputs.percentile_threshold = .03 + ''' + + input_spec = TCompCorInputSpec + output_spec = CompCorOutputSpec + + def _run_interface(self, runtime): + imgseries = nb.load(self.inputs.realigned_file).get_data() + + # From the paper: + # "For each voxel time series, the temporal standard deviation is + # defined as the standard deviation of the time series after the removal + # of low-frequency nuisance terms (e.g., linear and quadratic drift)." + imgseries = regress_poly(2, imgseries) + imgseries = imgseries - np.mean(imgseries, axis=1)[:, np.newaxis] + + time_voxels = imgseries.T + num_voxels = np.prod(time_voxels.shape[1:]) + + # "To construct the tSTD noise ROI, we sorted the voxels by their + # temporal standard deviation ..." + tSTD = self._compute_tSTD(time_voxels, 0) + sortSTD = np.sort(tSTD, axis=None) # flattened sorted matrix + + # use percentile_threshold to pick voxels + threshold_index = int(num_voxels * (1. - self.inputs.percentile_threshold)) + threshold_std = sortSTD[threshold_index] + mask = tSTD >= threshold_std + mask = mask.astype(int) + + # save mask + mask_file = 'mask.nii' + nb.nifti1.save(nb.Nifti1Image(mask, np.eye(4)), mask_file) + self.inputs.mask_file = mask_file + + super(TCompCor, self)._run_interface(runtime) + return runtime + +ACompCor = CompCor + +class TSNRInputSpec(BaseInterfaceInputSpec): + in_file = InputMultiPath(File(exists=True), mandatory=True, + desc='realigned 4D file or a list of 3D files') + regress_poly = traits.Range(low=1, desc='Remove polynomials') + tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False, + desc='output tSNR file') + mean_file = File('mean.nii.gz', usedefault=True, hash_files=False, + desc='output mean file') + stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False, + desc='output tSNR file') + detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False, + desc='input file after detrending') + + +class TSNROutputSpec(TraitedSpec): + tsnr_file = File(exists=True, desc='tsnr image file') + mean_file = File(exists=True, desc='mean image file') + stddev_file = File(exists=True, desc='std dev image file') + detrended_file = File(desc='detrended input file') + + +class TSNR(BaseInterface): + """Computes the time-course SNR for a time series + + Typically you want to run this on a realigned time-series. + + Example + ------- + + >>> tsnr = TSNR() + >>> tsnr.inputs.in_file = 'functional.nii' + >>> res = tsnr.run() # doctest: +SKIP + + """ + input_spec = TSNRInputSpec + output_spec = TSNROutputSpec + + def _run_interface(self, runtime): + img = nb.load(self.inputs.in_file[0]) + header = img.header.copy() + vollist = [nb.load(filename) for filename in self.inputs.in_file] + data = np.concatenate([vol.get_data().reshape( + vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3) + data = np.nan_to_num(data) + + if data.dtype.kind == 'i': + header.set_data_dtype(np.float32) + data = data.astype(np.float32) + + if isdefined(self.inputs.regress_poly): + data = regress_poly(self.inputs.regress_poly, data) + img = nb.Nifti1Image(data, img.get_affine(), header) + nb.save(img, op.abspath(self.inputs.detrended_file)) + + meanimg = np.mean(data, axis=3) + stddevimg = np.std(data, axis=3) + tsnr = np.zeros_like(meanimg) + tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3] + img = nb.Nifti1Image(tsnr, img.get_affine(), header) + nb.save(img, op.abspath(self.inputs.tsnr_file)) + img = nb.Nifti1Image(meanimg, img.get_affine(), header) + nb.save(img, op.abspath(self.inputs.mean_file)) + img = nb.Nifti1Image(stddevimg, img.get_affine(), header) + nb.save(img, op.abspath(self.inputs.stddev_file)) + return runtime + + def _list_outputs(self): + outputs = self._outputs().get() + for k in ['tsnr_file', 'mean_file', 'stddev_file']: + outputs[k] = op.abspath(getattr(self.inputs, k)) + + if isdefined(self.inputs.regress_poly): + outputs['detrended_file'] = op.abspath(self.inputs.detrended_file) + return outputs + +def regress_poly(degree, data): + ''' returns data with degree polynomial regressed out. + The last dimension (i.e. data.shape[-1]) should be time. + ''' + datashape = data.shape + timepoints = datashape[-1] + + # Rearrange all voxel-wise time-series in rows + data = data.reshape((-1, timepoints)) + + # Generate design matrix + X = np.ones((timepoints, 1)) + for i in range(degree): + polynomial_func = legendre(i+1) + value_array = np.linspace(-1, 1, timepoints) + X = np.hstack((X, polynomial_func(value_array)[:, np.newaxis])) + + # Calculate coefficients + betas = np.linalg.pinv(X).dot(data.T) + + # Estimation + datahat = X[:, 1:].dot(betas[1:, ...]).T + regressed_data = data - datahat + + # Back to original shape + return regressed_data.reshape(datashape) def compute_dvars(in_file, in_mask, remove_zerovariance=False): """ diff --git a/nipype/algorithms/misc.py b/nipype/algorithms/misc.py index 23fb1337e1..99e5126214 100644 --- a/nipype/algorithms/misc.py +++ b/nipype/algorithms/misc.py @@ -22,7 +22,6 @@ import numpy as np from math import floor, ceil from scipy.ndimage.morphology import grey_dilation -from scipy.special import legendre import scipy.io as sio import itertools import scipy.stats as stats @@ -35,6 +34,7 @@ BaseInterfaceInputSpec, isdefined, DynamicTraitedSpec, Undefined) from ..utils.filemanip import fname_presuffix, split_filename +from . import confounds iflogger = logging.getLogger('interface') @@ -258,108 +258,6 @@ def _list_outputs(self): outputs['nifti_file'] = self._gen_output_file_name() return outputs -class TSNRInputSpec(BaseInterfaceInputSpec): - in_file = InputMultiPath(File(exists=True), mandatory=True, - desc='realigned 4D file or a list of 3D files') - regress_poly = traits.Range(low=1, desc='Remove polynomials') - tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False, - desc='output tSNR file') - mean_file = File('mean.nii.gz', usedefault=True, hash_files=False, - desc='output mean file') - stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False, - desc='output tSNR file') - detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False, - desc='input file after detrending') - - -class TSNROutputSpec(TraitedSpec): - tsnr_file = File(exists=True, desc='tsnr image file') - mean_file = File(exists=True, desc='mean image file') - stddev_file = File(exists=True, desc='std dev image file') - detrended_file = File(desc='detrended input file') - - -class TSNR(BaseInterface): - """Computes the time-course SNR for a time series - - Typically you want to run this on a realigned time-series. - - Example - ------- - - >>> tsnr = TSNR() - >>> tsnr.inputs.in_file = 'functional.nii' - >>> res = tsnr.run() # doctest: +SKIP - - """ - input_spec = TSNRInputSpec - output_spec = TSNROutputSpec - - def _run_interface(self, runtime): - img = nb.load(self.inputs.in_file[0]) - header = img.header.copy() - vollist = [nb.load(filename) for filename in self.inputs.in_file] - data = np.concatenate([vol.get_data().reshape( - vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3) - data = np.nan_to_num(data) - - if data.dtype.kind == 'i': - header.set_data_dtype(np.float32) - data = data.astype(np.float32) - - if isdefined(self.inputs.regress_poly): - data = regress_poly(self.inputs.regress_poly, data) - img = nb.Nifti1Image(data, img.get_affine(), header) - nb.save(img, op.abspath(self.inputs.detrended_file)) - - meanimg = np.mean(data, axis=3) - stddevimg = np.std(data, axis=3) - tsnr = np.zeros_like(meanimg) - tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3] - img = nb.Nifti1Image(tsnr, img.get_affine(), header) - nb.save(img, op.abspath(self.inputs.tsnr_file)) - img = nb.Nifti1Image(meanimg, img.get_affine(), header) - nb.save(img, op.abspath(self.inputs.mean_file)) - img = nb.Nifti1Image(stddevimg, img.get_affine(), header) - nb.save(img, op.abspath(self.inputs.stddev_file)) - return runtime - - def _list_outputs(self): - outputs = self._outputs().get() - for k in ['tsnr_file', 'mean_file', 'stddev_file']: - outputs[k] = op.abspath(getattr(self.inputs, k)) - - if isdefined(self.inputs.regress_poly): - outputs['detrended_file'] = op.abspath(self.inputs.detrended_file) - return outputs - -def regress_poly(degree, data): - ''' returns data with degree polynomial regressed out. - The last dimension (i.e. data.shape[-1]) should be time. - ''' - datashape = data.shape - timepoints = datashape[-1] - - # Rearrange all voxel-wise time-series in rows - data = data.reshape((-1, timepoints)) - - # Generate design matrix - X = np.ones((timepoints, 1)) - for i in range(degree): - polynomial_func = legendre(i+1) - value_array = np.linspace(-1, 1, timepoints) - X = np.hstack((X, polynomial_func(value_array)[:, np.newaxis])) - - # Calculate coefficients - betas = np.linalg.pinv(X).dot(data.T) - - # Estimation - datahat = X[:, 1:].dot(betas[1:, ...]).T - regressed_data = data - datahat - - # Back to original shape - return regressed_data.reshape(datashape) - class GunzipInputSpec(BaseInterfaceInputSpec): in_file = File(exists=True, mandatory=True) @@ -1520,3 +1418,14 @@ def __init__(self, **inputs): warnings.warn(("This interface has been deprecated since 0.10.0," " please use nipype.algorithms.metrics.FuzzyOverlap"), DeprecationWarning) + +class TSNR(confounds.TSNR): + """ + .. deprecated:: 0.12.1 + Use :py:class:`nipype.algorithms.confounds.TSNR` instead + """ + def __init__(self, **inputs): + super(confounds.TSNR, self).__init__(**inputs) + warnings.warn(("This interface has been moved since 0.12.0," + " please use nipype.algorithms.confounds.TSNR"), + UserWarning) diff --git a/nipype/algorithms/tests/test_compcor.py b/nipype/algorithms/tests/test_compcor.py index 256c258a17..d7b81a8cd2 100644 --- a/nipype/algorithms/tests/test_compcor.py +++ b/nipype/algorithms/tests/test_compcor.py @@ -2,7 +2,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: import nipype from ...testing import assert_equal, assert_true, assert_false, skipif, utils -from ..compcor import CompCor, TCompCor, ACompCor +from ..confounds import CompCor, TCompCor, ACompCor import unittest import nibabel as nb diff --git a/nipype/algorithms/tests/test_tsnr.py b/nipype/algorithms/tests/test_tsnr.py index 3833d1f27f..9730193c6b 100644 --- a/nipype/algorithms/tests/test_tsnr.py +++ b/nipype/algorithms/tests/test_tsnr.py @@ -3,7 +3,8 @@ from ...testing import (assert_equal, assert_true, assert_almost_equal, skipif, utils) -from ..misc import TSNR +from ..confounds import TSNR +from .. import misc import unittest import mock @@ -85,6 +86,14 @@ def test_tsnr_withpoly3(self): 'tsnr_file': (2.6, 57.3) }) + @mock.patch('warnings.warn') + def test_warning(self, mock_warn): + # run + misc.TSNR(in_file=self.in_filenames['in_file']) + + # assert + mock_warn.assert_called_once_with(mock.ANY, UserWarning) + def assert_expected_outputs_poly(self, tsnrresult, expected_ranges): assert_equal(os.path.basename(tsnrresult.outputs.detrended_file), self.out_filenames['detrended_file']) diff --git a/nipype/workflows/rsfmri/fsl/resting.py b/nipype/workflows/rsfmri/fsl/resting.py index a2778fe2d9..a51693fda5 100644 --- a/nipype/workflows/rsfmri/fsl/resting.py +++ b/nipype/workflows/rsfmri/fsl/resting.py @@ -7,8 +7,7 @@ from ....interfaces import fsl as fsl # fsl from ....interfaces import utility as util # utility from ....pipeline import engine as pe # pypeline engine -from ....algorithms.misc import TSNR -from ....algorithms import compcor as cc +from ....algorithms import confounds def select_volume(filename, which): """Return the middle index of a file @@ -114,11 +113,11 @@ def create_resting_preproc(name='restpreproc', base_dir=None): name='outputspec') slicetimer = pe.Node(fsl.SliceTimer(), name='slicetimer') realigner = create_realign_flow() - tsnr = pe.Node(TSNR(regress_poly=2), name='tsnr') + tsnr = pe.Node(confounds.TSNR(regress_poly=2), name='tsnr') getthresh = pe.Node(interface=fsl.ImageStats(op_string='-p 98'), name='getthreshold') threshold_stddev = pe.Node(fsl.Threshold(), name='threshold') - compcor = pe.Node(cc.ACompCor(components_file="noise_components.txt", + compcor = pe.Node(confounds.ACompCor(components_file="noise_components.txt", use_regress_poly=False), name='compcor') remove_noise = pe.Node(fsl.FilterRegressor(filter_all=True),