|
22 | 22 | import numpy as np
|
23 | 23 | from math import floor, ceil
|
24 | 24 | from scipy.ndimage.morphology import grey_dilation
|
25 |
| -from scipy.special import legendre |
26 | 25 | import scipy.io as sio
|
27 | 26 | import itertools
|
28 | 27 | import scipy.stats as stats
|
|
35 | 34 | BaseInterfaceInputSpec, isdefined,
|
36 | 35 | DynamicTraitedSpec, Undefined)
|
37 | 36 | from ..utils.filemanip import fname_presuffix, split_filename
|
| 37 | +from . import confounds |
38 | 38 |
|
39 | 39 | iflogger = logging.getLogger('interface')
|
40 | 40 |
|
@@ -258,108 +258,6 @@ def _list_outputs(self):
|
258 | 258 | outputs['nifti_file'] = self._gen_output_file_name()
|
259 | 259 | return outputs
|
260 | 260 |
|
261 |
| -class TSNRInputSpec(BaseInterfaceInputSpec): |
262 |
| - in_file = InputMultiPath(File(exists=True), mandatory=True, |
263 |
| - desc='realigned 4D file or a list of 3D files') |
264 |
| - regress_poly = traits.Range(low=1, desc='Remove polynomials') |
265 |
| - tsnr_file = File('tsnr.nii.gz', usedefault=True, hash_files=False, |
266 |
| - desc='output tSNR file') |
267 |
| - mean_file = File('mean.nii.gz', usedefault=True, hash_files=False, |
268 |
| - desc='output mean file') |
269 |
| - stddev_file = File('stdev.nii.gz', usedefault=True, hash_files=False, |
270 |
| - desc='output tSNR file') |
271 |
| - detrended_file = File('detrend.nii.gz', usedefault=True, hash_files=False, |
272 |
| - desc='input file after detrending') |
273 |
| - |
274 |
| - |
275 |
| -class TSNROutputSpec(TraitedSpec): |
276 |
| - tsnr_file = File(exists=True, desc='tsnr image file') |
277 |
| - mean_file = File(exists=True, desc='mean image file') |
278 |
| - stddev_file = File(exists=True, desc='std dev image file') |
279 |
| - detrended_file = File(desc='detrended input file') |
280 |
| - |
281 |
| - |
282 |
| -class TSNR(BaseInterface): |
283 |
| - """Computes the time-course SNR for a time series |
284 |
| -
|
285 |
| - Typically you want to run this on a realigned time-series. |
286 |
| -
|
287 |
| - Example |
288 |
| - ------- |
289 |
| -
|
290 |
| - >>> tsnr = TSNR() |
291 |
| - >>> tsnr.inputs.in_file = 'functional.nii' |
292 |
| - >>> res = tsnr.run() # doctest: +SKIP |
293 |
| -
|
294 |
| - """ |
295 |
| - input_spec = TSNRInputSpec |
296 |
| - output_spec = TSNROutputSpec |
297 |
| - |
298 |
| - def _run_interface(self, runtime): |
299 |
| - img = nb.load(self.inputs.in_file[0]) |
300 |
| - header = img.header.copy() |
301 |
| - vollist = [nb.load(filename) for filename in self.inputs.in_file] |
302 |
| - data = np.concatenate([vol.get_data().reshape( |
303 |
| - vol.get_shape()[:3] + (-1,)) for vol in vollist], axis=3) |
304 |
| - data = np.nan_to_num(data) |
305 |
| - |
306 |
| - if data.dtype.kind == 'i': |
307 |
| - header.set_data_dtype(np.float32) |
308 |
| - data = data.astype(np.float32) |
309 |
| - |
310 |
| - if isdefined(self.inputs.regress_poly): |
311 |
| - data = regress_poly(self.inputs.regress_poly, data) |
312 |
| - img = nb.Nifti1Image(data, img.get_affine(), header) |
313 |
| - nb.save(img, op.abspath(self.inputs.detrended_file)) |
314 |
| - |
315 |
| - meanimg = np.mean(data, axis=3) |
316 |
| - stddevimg = np.std(data, axis=3) |
317 |
| - tsnr = np.zeros_like(meanimg) |
318 |
| - tsnr[stddevimg > 1.e-3] = meanimg[stddevimg > 1.e-3] / stddevimg[stddevimg > 1.e-3] |
319 |
| - img = nb.Nifti1Image(tsnr, img.get_affine(), header) |
320 |
| - nb.save(img, op.abspath(self.inputs.tsnr_file)) |
321 |
| - img = nb.Nifti1Image(meanimg, img.get_affine(), header) |
322 |
| - nb.save(img, op.abspath(self.inputs.mean_file)) |
323 |
| - img = nb.Nifti1Image(stddevimg, img.get_affine(), header) |
324 |
| - nb.save(img, op.abspath(self.inputs.stddev_file)) |
325 |
| - return runtime |
326 |
| - |
327 |
| - def _list_outputs(self): |
328 |
| - outputs = self._outputs().get() |
329 |
| - for k in ['tsnr_file', 'mean_file', 'stddev_file']: |
330 |
| - outputs[k] = op.abspath(getattr(self.inputs, k)) |
331 |
| - |
332 |
| - if isdefined(self.inputs.regress_poly): |
333 |
| - outputs['detrended_file'] = op.abspath(self.inputs.detrended_file) |
334 |
| - return outputs |
335 |
| - |
336 |
| -def regress_poly(degree, data): |
337 |
| - ''' returns data with degree polynomial regressed out. |
338 |
| - The last dimension (i.e. data.shape[-1]) should be time. |
339 |
| - ''' |
340 |
| - datashape = data.shape |
341 |
| - timepoints = datashape[-1] |
342 |
| - |
343 |
| - # Rearrange all voxel-wise time-series in rows |
344 |
| - data = data.reshape((-1, timepoints)) |
345 |
| - |
346 |
| - # Generate design matrix |
347 |
| - X = np.ones((timepoints, 1)) |
348 |
| - for i in range(degree): |
349 |
| - polynomial_func = legendre(i+1) |
350 |
| - value_array = np.linspace(-1, 1, timepoints) |
351 |
| - X = np.hstack((X, polynomial_func(value_array)[:, np.newaxis])) |
352 |
| - |
353 |
| - # Calculate coefficients |
354 |
| - betas = np.linalg.pinv(X).dot(data.T) |
355 |
| - |
356 |
| - # Estimation |
357 |
| - datahat = X[:, 1:].dot(betas[1:, ...]).T |
358 |
| - regressed_data = data - datahat |
359 |
| - |
360 |
| - # Back to original shape |
361 |
| - return regressed_data.reshape(datashape) |
362 |
| - |
363 | 261 | class GunzipInputSpec(BaseInterfaceInputSpec):
|
364 | 262 | in_file = File(exists=True, mandatory=True)
|
365 | 263 |
|
@@ -1520,3 +1418,14 @@ def __init__(self, **inputs):
|
1520 | 1418 | warnings.warn(("This interface has been deprecated since 0.10.0,"
|
1521 | 1419 | " please use nipype.algorithms.metrics.FuzzyOverlap"),
|
1522 | 1420 | DeprecationWarning)
|
| 1421 | + |
| 1422 | +class TSNR(confounds.TSNR): |
| 1423 | + """ |
| 1424 | + .. deprecated:: 0.12.1 |
| 1425 | + Use :py:class:`nipype.algorithms.confounds.TSNR` instead |
| 1426 | + """ |
| 1427 | + def __init__(self, **inputs): |
| 1428 | + super(confounds.TSNR, self).__init__(**inputs) |
| 1429 | + warnings.warn(("This interface has been deprecated since 0.12.0," |
| 1430 | + " please use nipype.algorithms.confounds.TSNR"), |
| 1431 | + DeprecationWarning) |
0 commit comments