@@ -345,6 +345,9 @@ class CompCorInputSpec(BaseInterfaceInputSpec):
345
345
'unspecified' )
346
346
save_pre_filter = traits .Either (
347
347
traits .Bool , File , desc = 'Save pre-filter basis as text file' )
348
+ ignore_initial_volumes = traits .Range (
349
+ low = 0 , usedefault = True ,
350
+ desc = 'Number of volumes at start of series to ignore' )
348
351
349
352
350
353
class CompCorOutputSpec (TraitedSpec ):
@@ -357,6 +360,26 @@ class CompCor(BaseInterface):
357
360
"""
358
361
Interface with core CompCor computation, used in aCompCor and tCompCor
359
362
363
+ CompCor provides three pre-filter options, all of which include per-voxel
364
+ mean removal:
365
+ - polynomial: Legendre polynomial basis
366
+ - cosine: Discrete cosine basis
367
+ - False: mean-removal only
368
+
369
+ In the case of ``polynomial`` and ``cosine`` filters, a pre-filter file may
370
+ be saved with a row for each volume/timepoint, and a column for each
371
+ non-constant regressor.
372
+ If no non-constant (mean-removal) columns are used, this file may be empty.
373
+
374
+ If ``ignore_initial_volumes`` is set, then the specified number of initial
375
+ volumes are excluded both from pre-filtering and CompCor component
376
+ extraction.
377
+ Each column in the components and pre-filter files are prefixe with zeros
378
+ for each excluded volume so that the number of rows continues to match the
379
+ number of volumes in the input file.
380
+ In addition, for each excluded volume, a column is added to the pre-filter
381
+ file with a 1 in the corresponding row.
382
+
360
383
Example
361
384
-------
362
385
@@ -417,6 +440,12 @@ def _run_interface(self, runtime):
417
440
header = imgseries .header )
418
441
mask_images = [img ]
419
442
443
+ skip_vols = self .inputs .ignore_initial_volumes
444
+ if skip_vols :
445
+ imgseries = imgseries .__class__ (
446
+ imgseries .get_data ()[..., skip_vols :], imgseries .affine ,
447
+ imgseries .header )
448
+
420
449
mask_images = self ._process_masks (mask_images , imgseries .get_data ())
421
450
422
451
TR = 0
@@ -441,6 +470,13 @@ def _run_interface(self, runtime):
441
470
imgseries .get_data (), mask_images , self .inputs .num_components ,
442
471
self .inputs .pre_filter , degree , self .inputs .high_pass_cutoff , TR )
443
472
473
+ if skip_vols :
474
+ old_comp = components
475
+ nrows = skip_vols + components .shape [0 ]
476
+ components = np .zeros ((nrows , components .shape [1 ]),
477
+ dtype = components .dtype )
478
+ components [skip_vols :] = old_comp
479
+
444
480
components_file = os .path .join (os .getcwd (), self .inputs .components_file )
445
481
np .savetxt (components_file , components , fmt = b"%.10f" , delimiter = '\t ' ,
446
482
header = self ._make_headers (components .shape [1 ]), comments = '' )
@@ -451,6 +487,15 @@ def _run_interface(self, runtime):
451
487
'cosine' : 'cos' }[self .inputs .pre_filter ]
452
488
ncols = filter_basis .shape [1 ] if filter_basis .size > 0 else 0
453
489
header = ['{}{:02d}' .format (ftype , i ) for i in range (ncols )]
490
+ if skip_vols :
491
+ old_basis = filter_basis
492
+ nrows = filter_basis .shape [0 ] if filter_basis .size > 0 else 0
493
+ filter_basis = np .zeros ((nrows + skip_vols , ncols + skip_vols ),
494
+ dtype = filter_basis .dtype )
495
+ filter_basis [skip_vols :, :ncols ] = old_basis
496
+ filter_basis [:skip_vols , - skip_vols :] = np .eye (skip_vols )
497
+ header .extend (['SteadyState{:02d}' .format (i )
498
+ for i in range (skip_vols )])
454
499
np .savetxt (pre_filter_file , filter_basis , fmt = b'%.10f' ,
455
500
delimiter = '\t ' , header = '\t ' .join (header ), comments = '' )
456
501
0 commit comments