12
12
13
13
'''
14
14
from __future__ import print_function , division , unicode_literals , absolute_import
15
- from builtins import str , zip , range , open
15
+ from builtins import range
16
16
17
17
import os
18
18
import os .path as op
19
19
20
20
import nibabel as nb
21
21
import numpy as np
22
- from scipy import linalg
23
- from scipy . special import legendre
22
+ from numpy . polynomial import Legendre
23
+ from scipy import linalg , signal
24
24
25
25
from .. import logging
26
- from ..external .due import due , Doi , BibTeX
26
+ from ..external .due import BibTeX
27
27
from ..interfaces .base import (traits , TraitedSpec , BaseInterface ,
28
28
BaseInterfaceInputSpec , File , isdefined ,
29
29
InputMultiPath )
@@ -160,8 +160,8 @@ def _run_interface(self, runtime):
160
160
'dvars_nstd' , ext = self .inputs .figformat )
161
161
fig = plot_confound (dvars [1 ], self .inputs .figsize , 'DVARS' , series_tr = tr )
162
162
fig .savefig (self ._results ['fig_nstd' ], dpi = float (self .inputs .figdpi ),
163
- format = self .inputs .figformat ,
164
- bbox_inches = 'tight' )
163
+ format = self .inputs .figformat ,
164
+ bbox_inches = 'tight' )
165
165
fig .clf ()
166
166
167
167
if self .inputs .save_vxstd :
@@ -175,8 +175,8 @@ def _run_interface(self, runtime):
175
175
fig = plot_confound (dvars [2 ], self .inputs .figsize , 'Voxelwise std DVARS' ,
176
176
series_tr = tr )
177
177
fig .savefig (self ._results ['fig_vxstd' ], dpi = float (self .inputs .figdpi ),
178
- format = self .inputs .figformat ,
179
- bbox_inches = 'tight' )
178
+ format = self .inputs .figformat ,
179
+ bbox_inches = 'tight' )
180
180
fig .clf ()
181
181
182
182
if self .inputs .save_all :
@@ -323,9 +323,9 @@ class CompCor(BaseInterface):
323
323
"author = {Behzadi, Yashar and Restom, Khaled and Liau, Joy and Liu, Thomas T.},"
324
324
"year = {2007},"
325
325
"pages = {90-101},}"
326
- ),
326
+ ),
327
327
'tags' : ['method' , 'implementation' ]
328
- }]
328
+ }]
329
329
330
330
def _run_interface (self , runtime ):
331
331
imgseries = nb .load (self .inputs .realigned_file ).get_data ()
@@ -337,18 +337,13 @@ def _run_interface(self, runtime):
337
337
# from paper:
338
338
# "The constant and linear trends of the columns in the matrix M were
339
339
# removed [prior to ...]"
340
- if self .inputs .use_regress_poly :
341
- voxel_timecourses = regress_poly (self .inputs .regress_poly_degree ,
342
- voxel_timecourses )
343
- voxel_timecourses = voxel_timecourses - np .mean (voxel_timecourses ,
344
- axis = 1 )[:, np .newaxis ]
340
+ degree = self .inputs .regress_poly_degree if self .inputs .use_regress_poly else 0
341
+ voxel_timecourses = regress_poly (degree , voxel_timecourses )
345
342
346
343
# "Voxel time series from the noise ROI (either anatomical or tSTD) were
347
344
# placed in a matrix M of size Nxm, with time along the row dimension
348
345
# and voxels along the column dimension."
349
346
M = voxel_timecourses .T
350
- numvols = M .shape [0 ]
351
- numvoxels = M .shape [1 ]
352
347
353
348
# "[... were removed] prior to column-wise variance normalization."
354
349
M = M / self ._compute_tSTD (M , 1. )
@@ -412,7 +407,6 @@ def _run_interface(self, runtime):
412
407
# defined as the standard deviation of the time series after the removal
413
408
# of low-frequency nuisance terms (e.g., linear and quadratic drift)."
414
409
imgseries = regress_poly (2 , imgseries )
415
- imgseries = imgseries - np .mean (imgseries , axis = 1 )[:, np .newaxis ]
416
410
417
411
time_voxels = imgseries .T
418
412
num_voxels = np .prod (time_voxels .shape [1 :])
@@ -488,7 +482,7 @@ def _run_interface(self, runtime):
488
482
data = data .astype (np .float32 )
489
483
490
484
if isdefined (self .inputs .regress_poly ):
491
- data = regress_poly (self .inputs .regress_poly , data )
485
+ data = regress_poly (self .inputs .regress_poly , data , remove_mean = False )
492
486
img = nb .Nifti1Image (data , img .get_affine (), header )
493
487
nb .save (img , op .abspath (self .inputs .detrended_file ))
494
488
@@ -513,28 +507,33 @@ def _list_outputs(self):
513
507
outputs ['detrended_file' ] = op .abspath (self .inputs .detrended_file )
514
508
return outputs
515
509
516
- def regress_poly (degree , data ):
510
+ def regress_poly (degree , data , remove_mean = True , axis = - 1 ):
517
511
''' returns data with degree polynomial regressed out.
518
- The last dimension (i.e. data.shape[-1]) should be time.
512
+ Be default it is calculated along the last axis (usu. time).
513
+ If remove_mean is True (default), the data is demeaned (i.e. degree 0).
514
+ If remove_mean is false, the data is not.
519
515
'''
520
516
datashape = data .shape
521
- timepoints = datashape [- 1 ]
517
+ timepoints = datashape [axis ]
522
518
523
519
# Rearrange all voxel-wise time-series in rows
524
520
data = data .reshape ((- 1 , timepoints ))
525
521
526
522
# Generate design matrix
527
- X = np .ones ((timepoints , 1 ))
523
+ X = np .ones ((timepoints , 1 )) # quick way to calc degree 0
528
524
for i in range (degree ):
529
- polynomial_func = legendre ( i + 1 )
525
+ polynomial_func = Legendre . basis ( i + 1 )
530
526
value_array = np .linspace (- 1 , 1 , timepoints )
531
527
X = np .hstack ((X , polynomial_func (value_array )[:, np .newaxis ]))
532
528
533
529
# Calculate coefficients
534
530
betas = np .linalg .pinv (X ).dot (data .T )
535
531
536
532
# Estimation
537
- datahat = X [:, 1 :].dot (betas [1 :, ...]).T
533
+ if remove_mean :
534
+ datahat = X .dot (betas ).T
535
+ else : # disregard the first layer of X, which is degree 0
536
+ datahat = X [:, 1 :].dot (betas [1 :, ...]).T
538
537
regressed_data = data - datahat
539
538
540
539
# Back to original shape
@@ -569,7 +568,6 @@ def compute_dvars(in_file, in_mask, remove_zerovariance=False):
569
568
:return: the standardized DVARS
570
569
571
570
"""
572
- import os .path as op
573
571
import numpy as np
574
572
import nibabel as nb
575
573
from nitime .algorithms import AR_est_YW
@@ -594,7 +592,7 @@ def compute_dvars(in_file, in_mask, remove_zerovariance=False):
594
592
mfunc = func [idx [0 ], idx [1 ], idx [2 ], :]
595
593
596
594
# Demean
597
- mfunc -= mfunc . mean ( axis = 1 ).astype (np .float32 )[..., np . newaxis ]
595
+ mfunc = regress_poly ( 0 , mfunc , remove_mean = True ).astype (np .float32 )
598
596
599
597
# Compute (non-robust) estimate of lag-1 autocorrelation
600
598
ar1 = np .apply_along_axis (AR_est_YW , 1 , mfunc , 1 )[:, 0 ]
0 commit comments