Skip to content

Commit 33d2f30

Browse files
author
Shoshana Berleant
committed
move tsnr to own file
1 parent 87108d9 commit 33d2f30

File tree

2 files changed

+109
-87
lines changed

2 files changed

+109
-87
lines changed

nipype/algorithms/misc.py

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
BaseInterfaceInputSpec, isdefined,
4040
DynamicTraitedSpec, Undefined)
4141
from nipype.utils.filemanip import fname_presuffix, split_filename
42+
43+
# for backwards compatibility
44+
from nipype.algorithms.tsnr import TSNR
45+
4246
iflogger = logging.getLogger('interface')
4347

4448

@@ -259,93 +263,6 @@ def _list_outputs(self):
259263
outputs['nifti_file'] = self._gen_output_file_name()
260264
return outputs
261265

262-
263-
class TSNRInputSpec(BaseInterfaceInputSpec):
264-
in_file = InputMultiPath(File(exists=True), mandatory=True,
265-
desc='realigned 4D file or a list of 3D files')
266-
regress_poly = traits.Range(low=1, desc='Remove polynomials')
267-
tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False,
268-
desc='output tSNR file')
269-
mean_file = File('mean.nii.gz', usedefault=True, hash_files=False,
270-
desc='output mean file')
271-
stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False,
272-
desc='output tSNR file')
273-
detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False,
274-
desc='input file after detrending')
275-
276-
277-
class TSNROutputSpec(TraitedSpec):
278-
tsnr_file = File(exists=True, desc='tsnr image file')
279-
mean_file = File(exists=True, desc='mean image file')
280-
stddev_file = File(exists=True, desc='std dev image file')
281-
detrended_file = File(desc='detrended input file')
282-
283-
284-
class TSNR(BaseInterface):
285-
"""Computes the time-course SNR for a time series
286-
287-
Typically you want to run this on a realigned time-series.
288-
289-
Example
290-
-------
291-
292-
>>> tsnr = TSNR()
293-
>>> tsnr.inputs.in_file = 'functional.nii'
294-
>>> res = tsnr.run() # doctest: +SKIP
295-
296-
"""
297-
input_spec = TSNRInputSpec
298-
output_spec = TSNROutputSpec
299-
300-
def _run_interface(self, runtime):
301-
img = nb.load(self.inputs.in_file[0])
302-
header = img.header.copy()
303-
vollist = [nb.load(filename) for filename in self.inputs.in_file]
304-
data = np.concatenate([vol.get_data().reshape(
305-
vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3)
306-
data = np.nan_to_num(data)
307-
308-
if data.dtype.kind == 'i':
309-
header.set_data_dtype(np.float32)
310-
data = data.astype(np.float32)
311-
312-
if isdefined(self.inputs.regress_poly):
313-
timepoints = img.shape[-1]
314-
X = np.ones((timepoints, 1))
315-
for i in range(self.inputs.regress_poly):
316-
X = np.hstack((X, legendre(
317-
i + 1)(np.linspace(-1, 1, timepoints))[:, None]))
318-
betas = np.dot(np.linalg.pinv(X), np.rollaxis(data, 3, 2))
319-
datahat = np.rollaxis(np.dot(X[:, 1:],
320-
np.rollaxis(
321-
betas[1:, :, :, :], 0, 3)),
322-
0, 4)
323-
data = data - datahat
324-
img = nb.Nifti1Image(data, img.get_affine(), header)
325-
nb.save(img, op.abspath(self.inputs.detrended_file))
326-
327-
meanimg = np.mean(data, axis=3)
328-
stddevimg = np.std(data, axis=3)
329-
tsnr = np.zeros_like(meanimg)
330-
tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3]
331-
img = nb.Nifti1Image(tsnr, img.get_affine(), header)
332-
nb.save(img, op.abspath(self.inputs.tsnr_file))
333-
img = nb.Nifti1Image(meanimg, img.get_affine(), header)
334-
nb.save(img, op.abspath(self.inputs.mean_file))
335-
img = nb.Nifti1Image(stddevimg, img.get_affine(), header)
336-
nb.save(img, op.abspath(self.inputs.stddev_file))
337-
return runtime
338-
339-
def _list_outputs(self):
340-
outputs = self._outputs().get()
341-
for k in ['tsnr_file', 'mean_file', 'stddev_file']:
342-
outputs[k] = op.abspath(getattr(self.inputs, k))
343-
344-
if isdefined(self.inputs.regress_poly):
345-
outputs['detrended_file'] = op.abspath(self.inputs.detrended_file)
346-
return outputs
347-
348-
349266
class GunzipInputSpec(BaseInterfaceInputSpec):
350267
in_file = File(exists=True, mandatory=True)
351268

nipype/algorithms/tsnr.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
'''
4+
Miscellaneous algorithms
5+
6+
Change directory to provide relative paths for doctests
7+
>>> import os
8+
>>> filepath = os.path.dirname(os.path.realpath(__file__))
9+
>>> datadir = os.path.realpath(os.path.join(filepath, '../testing/data'))
10+
>>> os.chdir(datadir)
11+
12+
'''
13+
from nipype.interfaces.base import (BaseInterface, traits, TraitedSpec, File,
14+
InputMultiPath, BaseInterfaceInputSpec,
15+
isdefined)
16+
17+
import nibabel as nb
18+
import numpy as np
19+
import os.path as op
20+
from scipy.special import legendre
21+
22+
class TSNRInputSpec(BaseInterfaceInputSpec):
23+
in_file = InputMultiPath(File(exists=True), mandatory=True,
24+
desc='realigned 4D file or a list of 3D files')
25+
regress_poly = traits.Range(low=1, desc='Remove polynomials')
26+
tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False,
27+
desc='output tSNR file')
28+
mean_file = File('mean.nii.gz', usedefault=True, hash_files=False,
29+
desc='output mean file')
30+
stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False,
31+
desc='output tSNR file')
32+
detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False,
33+
desc='input file after detrending')
34+
35+
36+
class TSNROutputSpec(TraitedSpec):
37+
tsnr_file = File(exists=True, desc='tsnr image file')
38+
mean_file = File(exists=True, desc='mean image file')
39+
stddev_file = File(exists=True, desc='std dev image file')
40+
detrended_file = File(desc='detrended input file')
41+
42+
43+
class TSNR(BaseInterface):
44+
"""Computes the time-course SNR for a time series
45+
46+
Typically you want to run this on a realigned time-series.
47+
48+
Example
49+
-------
50+
51+
>>> tsnr = TSNR()
52+
>>> tsnr.inputs.in_file = 'functional.nii'
53+
>>> res = tsnr.run() # doctest: +SKIP
54+
55+
"""
56+
input_spec = TSNRInputSpec
57+
output_spec = TSNROutputSpec
58+
59+
def _run_interface(self, runtime):
60+
img = nb.load(self.inputs.in_file[0])
61+
header = img.header.copy()
62+
vollist = [nb.load(filename) for filename in self.inputs.in_file]
63+
data = np.concatenate([vol.get_data().reshape(
64+
vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3)
65+
data = np.nan_to_num(data)
66+
67+
if data.dtype.kind == 'i':
68+
header.set_data_dtype(np.float32)
69+
data = data.astype(np.float32)
70+
71+
if isdefined(self.inputs.regress_poly):
72+
timepoints = img.shape[-1]
73+
X = np.ones((timepoints, 1))
74+
for i in range(self.inputs.regress_poly):
75+
X = np.hstack((X, legendre(
76+
i + 1)(np.linspace(-1, 1, timepoints))[:, None]))
77+
betas = np.dot(np.linalg.pinv(X), np.rollaxis(data, 3, 2))
78+
datahat = np.rollaxis(np.dot(X[:, 1:],
79+
np.rollaxis(
80+
betas[1:, :, :, :], 0, 3)),
81+
0, 4)
82+
data = data - datahat
83+
img = nb.Nifti1Image(data, img.get_affine(), header)
84+
nb.save(img, op.abspath(self.inputs.detrended_file))
85+
86+
meanimg = np.mean(data, axis=3)
87+
stddevimg = np.std(data, axis=3)
88+
tsnr = np.zeros_like(meanimg)
89+
tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3]
90+
img = nb.Nifti1Image(tsnr, img.get_affine(), header)
91+
nb.save(img, op.abspath(self.inputs.tsnr_file))
92+
img = nb.Nifti1Image(meanimg, img.get_affine(), header)
93+
nb.save(img, op.abspath(self.inputs.mean_file))
94+
img = nb.Nifti1Image(stddevimg, img.get_affine(), header)
95+
nb.save(img, op.abspath(self.inputs.stddev_file))
96+
return runtime
97+
98+
def _list_outputs(self):
99+
outputs = self._outputs().get()
100+
for k in ['tsnr_file', 'mean_file', 'stddev_file']:
101+
outputs[k] = op.abspath(getattr(self.inputs, k))
102+
103+
if isdefined(self.inputs.regress_poly):
104+
outputs['detrended_file'] = op.abspath(self.inputs.detrended_file)
105+
return outputs

0 commit comments

Comments
 (0)