Skip to content

Commit a6ddad8

Browse files
committed
Merge branch 'master' into fix_afni_allineate
2 parents 0d21a92 + 9b0686d commit a6ddad8

File tree

5 files changed

+103
-38
lines changed

5 files changed

+103
-38
lines changed

nipype/algorithms/confounds.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ class CompCorInputSpec(BaseInterfaceInputSpec):
345345
'unspecified')
346346
save_pre_filter = traits.Either(
347347
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')
348351

349352

350353
class CompCorOutputSpec(TraitedSpec):
@@ -357,6 +360,26 @@ class CompCor(BaseInterface):
357360
"""
358361
Interface with core CompCor computation, used in aCompCor and tCompCor
359362
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+
360383
Example
361384
-------
362385
@@ -417,6 +440,12 @@ def _run_interface(self, runtime):
417440
header=imgseries.header)
418441
mask_images = [img]
419442

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+
420449
mask_images = self._process_masks(mask_images, imgseries.get_data())
421450

422451
TR = 0
@@ -441,6 +470,13 @@ def _run_interface(self, runtime):
441470
imgseries.get_data(), mask_images, self.inputs.num_components,
442471
self.inputs.pre_filter, degree, self.inputs.high_pass_cutoff, TR)
443472

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+
444480
components_file = os.path.join(os.getcwd(), self.inputs.components_file)
445481
np.savetxt(components_file, components, fmt=b"%.10f", delimiter='\t',
446482
header=self._make_headers(components.shape[1]), comments='')
@@ -451,6 +487,15 @@ def _run_interface(self, runtime):
451487
'cosine': 'cos'}[self.inputs.pre_filter]
452488
ncols = filter_basis.shape[1] if filter_basis.size > 0 else 0
453489
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)])
454499
np.savetxt(pre_filter_file, filter_basis, fmt=b'%.10f',
455500
delimiter='\t', header='\t'.join(header), comments='')
456501

nipype/algorithms/tests/test_auto_ACompCor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def test_ACompCor_inputs():
1212
ignore_exception=dict(nohash=True,
1313
usedefault=True,
1414
),
15+
ignore_initial_volumes=dict(usedefault=True,
16+
),
1517
mask_files=dict(),
1618
mask_index=dict(requires=['mask_files'],
1719
xor=['merge_method'],

nipype/algorithms/tests/test_auto_TCompCor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def test_TCompCor_inputs():
1212
ignore_exception=dict(nohash=True,
1313
usedefault=True,
1414
),
15+
ignore_initial_volumes=dict(usedefault=True,
16+
),
1517
mask_files=dict(),
1618
mask_index=dict(requires=['mask_files'],
1719
xor=['merge_method'],

nipype/interfaces/freesurfer/longitudinal.py

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,55 +13,66 @@
1313
from __future__ import print_function, division, unicode_literals, absolute_import
1414

1515
import os
16-
#import itertools
1716

1817
from ... import logging
1918
from ..base import (TraitedSpec, File, traits,
2019
InputMultiPath, OutputMultiPath, isdefined)
21-
from .base import FSCommand, FSTraitedSpec
20+
from .base import (FSCommand, FSTraitedSpec, FSCommandOpenMP,
21+
FSTraitedSpecOpenMP)
2222

2323
__docformat__ = 'restructuredtext'
2424
iflogger = logging.getLogger('interface')
2525

2626

27-
class RobustTemplateInputSpec(FSTraitedSpec):
27+
class RobustTemplateInputSpec(FSTraitedSpecOpenMP):
2828
# required
29-
in_files = InputMultiPath(File(exists=True), mandatory=True, argstr='--mov %s',
30-
desc='input movable volumes to be aligned to common mean/median template')
29+
in_files = InputMultiPath(
30+
File(exists=True), mandatory=True, argstr='--mov %s',
31+
desc='input movable volumes to be aligned to common mean/median '
32+
'template')
3133
out_file = File('mri_robust_template_out.mgz', mandatory=True,
3234
usedefault=True, argstr='--template %s',
3335
desc='output template volume (final mean/median image)')
34-
auto_detect_sensitivity = traits.Bool(argstr='--satit', xor=['outlier_sensitivity'], mandatory=True,
35-
desc='auto-detect good sensitivity (recommended for head or full brain scans)')
36-
outlier_sensitivity = traits.Float(argstr='--sat %.4f', xor=['auto_detect_sensitivity'], mandatory=True,
37-
desc='set outlier sensitivity manually (e.g. "--sat 4.685" ). Higher values mean ' +
38-
'less sensitivity.')
36+
auto_detect_sensitivity = traits.Bool(
37+
argstr='--satit', xor=['outlier_sensitivity'], mandatory=True,
38+
desc='auto-detect good sensitivity (recommended for head or full '
39+
'brain scans)')
40+
outlier_sensitivity = traits.Float(
41+
argstr='--sat %.4f', xor=['auto_detect_sensitivity'], mandatory=True,
42+
desc='set outlier sensitivity manually (e.g. "--sat 4.685" ). Higher '
43+
'values mean less sensitivity.')
3944
# optional
40-
transform_outputs = InputMultiPath(File(exists=False),
41-
argstr='--lta %s',
42-
desc='output xforms to template (for each input)')
43-
intensity_scaling = traits.Bool(default_value=False,
44-
argstr='--iscale',
45-
desc='allow also intensity scaling (default off)')
46-
scaled_intensity_outputs = InputMultiPath(File(exists=False),
47-
argstr='--iscaleout %s',
48-
desc='final intensity scales (will activate --iscale)')
49-
subsample_threshold = traits.Int(argstr='--subsample %d',
50-
desc='subsample if dim > # on all axes (default no subs.)')
51-
average_metric = traits.Enum('median', 'mean', argstr='--average %d',
52-
desc='construct template from: 0 Mean, 1 Median (default)')
53-
initial_timepoint = traits.Int(argstr='--inittp %d',
54-
desc='use TP# for spacial init (default random), 0: no init')
55-
fixed_timepoint = traits.Bool(default_value=False, argstr='--fixtp',
56-
desc='map everthing to init TP# (init TP is not resampled)')
57-
no_iteration = traits.Bool(default_value=False, argstr='--noit',
58-
desc='do not iterate, just create first template')
59-
initial_transforms = InputMultiPath(File(exists=True),
60-
argstr='--ixforms %s',
61-
desc='use initial transforms (lta) on source')
62-
in_intensity_scales = InputMultiPath(File(exists=True),
63-
argstr='--iscalein %s',
64-
desc='use initial intensity scales')
45+
transform_outputs = InputMultiPath(
46+
File(exists=False), argstr='--lta %s',
47+
desc='output xforms to template (for each input)')
48+
intensity_scaling = traits.Bool(
49+
default_value=False, argstr='--iscale',
50+
desc='allow also intensity scaling (default off)')
51+
scaled_intensity_outputs = InputMultiPath(
52+
File(exists=False), argstr='--iscaleout %s',
53+
desc='final intensity scales (will activate --iscale)')
54+
subsample_threshold = traits.Int(
55+
argstr='--subsample %d',
56+
desc='subsample if dim > # on all axes (default no subs.)')
57+
average_metric = traits.Enum(
58+
'median', 'mean', argstr='--average %d',
59+
desc='construct template from: 0 Mean, 1 Median (default)')
60+
initial_timepoint = traits.Int(
61+
argstr='--inittp %d',
62+
desc='use TP# for spacial init (default random), 0: no init')
63+
fixed_timepoint = traits.Bool(
64+
default_value=False, argstr='--fixtp',
65+
desc='map everthing to init TP# (init TP is not resampled)')
66+
no_iteration = traits.Bool(
67+
default_value=False, argstr='--noit',
68+
desc='do not iterate, just create first template')
69+
initial_transforms = InputMultiPath(
70+
File(exists=True), argstr='--ixforms %s',
71+
desc='use initial transforms (lta) on source')
72+
in_intensity_scales = InputMultiPath(
73+
File(exists=True), argstr='--iscalein %s',
74+
desc='use initial intensity scales')
75+
6576

6677
class RobustTemplateOutputSpec(TraitedSpec):
6778
out_file = File(
@@ -72,7 +83,7 @@ class RobustTemplateOutputSpec(TraitedSpec):
7283
File(exists=True), desc="output final intensity scales")
7384

7485

75-
class RobustTemplate(FSCommand):
86+
class RobustTemplate(FSCommandOpenMP):
7687
""" construct an unbiased robust template for longitudinal volumes
7788
7889
Examples
@@ -92,8 +103,10 @@ class RobustTemplate(FSCommand):
92103
>>> template.cmdline #doctest: +NORMALIZE_WHITESPACE +ALLOW_UNICODE
93104
'mri_robust_template --satit --average 0 --fixtp --mov structural.nii functional.nii --inittp 1 --noit --template T1.nii --subsample 200'
94105
95-
>>> template.inputs.transform_outputs = ['structural.lta', 'functional.lta']
96-
>>> template.inputs.scaled_intensity_outputs = ['structural-iscale.txt', 'functional-iscale.txt']
106+
>>> template.inputs.transform_outputs = ['structural.lta',
107+
... 'functional.lta']
108+
>>> template.inputs.scaled_intensity_outputs = ['structural-iscale.txt',
109+
... 'functional-iscale.txt']
97110
>>> template.cmdline #doctest: +NORMALIZE_WHITESPACE +ALLOW_UNICODE
98111
'mri_robust_template --satit --average 0 --fixtp --mov structural.nii functional.nii --inittp 1 --noit --template T1.nii --iscaleout structural-iscale.txt functional-iscale.txt --subsample 200 --lta structural.lta functional.lta'
99112
@@ -151,9 +164,11 @@ class FuseSegmentationsInputSpec(FSTraitedSpec):
151164
must include the corresponding norm file for all given timepoints \
152165
as well as for the current subject")
153166

167+
154168
class FuseSegmentationsOutputSpec(TraitedSpec):
155169
out_file = File(exists=False, desc="output fused segmentation file")
156170

171+
157172
class FuseSegmentations(FSCommand):
158173

159174
""" fuse segmentations together from multiple timepoints

nipype/interfaces/freesurfer/tests/test_auto_RobustTemplate.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def test_RobustTemplate_inputs():
3333
),
3434
no_iteration=dict(argstr='--noit',
3535
),
36+
num_threads=dict(),
3637
out_file=dict(argstr='--template %s',
3738
mandatory=True,
3839
usedefault=True,

0 commit comments

Comments
 (0)