From 67054f44a934d59d9f8c7fede01735cb5ade29a6 Mon Sep 17 00:00:00 2001 From: mathiasg Date: Thu, 31 Jan 2019 16:34:36 -0500 Subject: [PATCH 1/2] enh: wb cifti-smoothing --- nipype/interfaces/workbench/__init__.py | 1 + nipype/interfaces/workbench/cifti.py | 144 ++++++++++++++++++ .../workbench/tests/test_auto_CiftiSmooth.py | 95 ++++++++++++ .../sub-01.L.midthickness.32k_fs_LR.surf.gii | 0 .../sub-01.R.midthickness.32k_fs_LR.surf.gii | 0 .../data/sub-01_task-rest.dtseries.nii | 0 6 files changed, 240 insertions(+) create mode 100644 nipype/interfaces/workbench/cifti.py create mode 100644 nipype/interfaces/workbench/tests/test_auto_CiftiSmooth.py create mode 100644 nipype/testing/data/sub-01.L.midthickness.32k_fs_LR.surf.gii create mode 100644 nipype/testing/data/sub-01.R.midthickness.32k_fs_LR.surf.gii create mode 100644 nipype/testing/data/sub-01_task-rest.dtseries.nii diff --git a/nipype/interfaces/workbench/__init__.py b/nipype/interfaces/workbench/__init__.py index 5ced0d2fb3..1de46f8953 100644 --- a/nipype/interfaces/workbench/__init__.py +++ b/nipype/interfaces/workbench/__init__.py @@ -3,3 +3,4 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: from .metric import MetricResample +from .cifti import CiftiSmooth diff --git a/nipype/interfaces/workbench/cifti.py b/nipype/interfaces/workbench/cifti.py new file mode 100644 index 0000000000..c7244c02c7 --- /dev/null +++ b/nipype/interfaces/workbench/cifti.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +"""This module provides interfaces for workbench CIFTI commands""" +from __future__ import (print_function, division, unicode_literals, + absolute_import) +import os + +from ..base import (TraitedSpec, File, traits, CommandLineInputSpec) +from .base import WBCommand +from ... import logging + +iflogger = logging.getLogger('nipype.interface') + + +class CiftiSmoothInputSpec(CommandLineInputSpec): + in_file = File( + exists=True, + mandatory=True, + argstr="%s", + position=0, + desc="The input CIFTI file") + sigma_surf = traits.Float( + mandatory=True, + argstr="%s", + position=1, + desc="the sigma for the gaussian surface smoothing kernel, in mm") + sigma_vol = traits.Float( + mandatory=True, + argstr="%s", + position=2, + desc="the sigma for the gaussian volume smoothing kernel, in mm") + direction = traits.Enum( + "ROW", + "COLUMN", + mandatory=True, + argstr="%s", + position=3, + desc="which dimension to smooth along, ROW or COLUMN") + out_file = File( + name_source=["in_file"], + name_template="smoothed_%s.nii", + keep_extension=True, + argstr="%s", + position=4, + desc="The output CIFTI") + left_surf = File( + exists=True, + mandatory=True, + position=5, + argstr="-left-surface %s", + desc="Specify the left surface to use") + left_corrected_areas = File( + exists=True, + position=6, + argstr="-left-corrected-areas %s", + desc="vertex areas (as a metric) to use instead of computing them from " + "the left surface.") + right_surf = File( + exists=True, + mandatory=True, + position=7, + argstr="-right-surface %s", + desc="Specify the right surface to use") + right_corrected_areas = File( + exists=True, + position=8, + argstr="-right-corrected-areas %s", + desc="vertex areas (as a metric) to use instead of computing them from " + "the right surface") + cerebellum_surf = File( + exists=True, + position=9, + argstr="-cerebellum-surface %s", + desc="specify the cerebellum surface to use") + cerebellum_corrected_areas = File( + exists=True, + position=10, + requires=["cerebellum_surf"], + argstr="cerebellum-corrected-areas %s", + desc="vertex areas (as a metric) to use instead of computing them from " + "the cerebellum surface") + cifti_roi = File( + exists=True, + position=11, + argstr="-cifti-roi %s", + desc="CIFTI file for ROI smoothing") + fix_zeros_vol = traits.Bool( + position=12, + argstr="-fix-zeros-volume", + desc="treat values of zero in the volume as missing data") + fix_zeros_surf = traits.Bool( + position=13, + argstr="-fix-zeros-surface", + desc="treat values of zero on the surface as missing data") + merged_volume = traits.Bool( + position=14, + argstr="-merged-volume", + desc="smooth across subcortical structure boundaries") + + +class CiftiSmoothOutputSpec(TraitedSpec): + out_file = File(exists=True, desc="output CIFTI file") + + +class CiftiSmooth(WBCommand): + """ + Smooth a CIFTI file + + The input cifti file must have a brain models mapping on the chosen + dimension, columns for .dtseries, and either for .dconn. By default, + data in different structures is smoothed independently (i.e., "parcel + constrained" smoothing), so volume structures that touch do not smooth + across this boundary. Specify ``merged_volume`` to ignore these + boundaries. Surface smoothing uses the ``GEO_GAUSS_AREA`` smoothing method. + + The ``*_corrected_areas`` options are intended for when it is unavoidable + to smooth on group average surfaces, it is only an approximate correction + for the reduction of structure in a group average surface. It is better + to smooth the data on individuals before averaging, when feasible. + + The ``fix_zeros_*`` options will treat values of zero as lack of data, and + not use that value when generating the smoothed values, but will fill + zeros with extrapolated values. The ROI should have a brain models + mapping along columns, exactly matching the mapping of the chosen + direction in the input file. Data outside the ROI is ignored. + + >>> from nipype.interfaces.workbench import CiftiSmooth + >>> smooth = CiftiSmooth() + >>> smooth.inputs.in_file = 'sub-01_task-rest.dtseries.nii' + >>> smooth.inputs.sigma_surf = 4 + >>> smooth.inputs.sigma_vol = 4 + >>> smooth.inputs.direction = 'COLUMN' + >>> smooth.inputs.right_surf = 'sub-01.R.midthickness.32k_fs_LR.surf.gii' + >>> smooth.inputs.left_surf = 'sub-01.L.midthickness.32k_fs_LR.surf.gii' + >>> smooth.cmdline + 'wb_command -cifti-smoothing sub-01_task-rest.dtseries.nii 4.0 4.0 COLUMN \ + smoothed_sub-01_task-rest.dtseries.nii \ + -left-surface sub-01.L.midthickness.32k_fs_LR.surf.gii \ + -right-surface sub-01.R.midthickness.32k_fs_LR.surf.gii' + """ + input_spec = CiftiSmoothInputSpec + output_spec = CiftiSmoothOutputSpec + _cmd = 'wb_command -cifti-smoothing' diff --git a/nipype/interfaces/workbench/tests/test_auto_CiftiSmooth.py b/nipype/interfaces/workbench/tests/test_auto_CiftiSmooth.py new file mode 100644 index 0000000000..b510a3b34e --- /dev/null +++ b/nipype/interfaces/workbench/tests/test_auto_CiftiSmooth.py @@ -0,0 +1,95 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..cifti import CiftiSmooth + + +def test_CiftiSmooth_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + cerebellum_corrected_areas=dict( + argstr='cerebellum-corrected-areas %s', + position=10, + requires=['cerebellum_surf'], + ), + cerebellum_surf=dict( + argstr='-cerebellum-surface %s', + position=9, + ), + cifti_roi=dict( + argstr='-cifti-roi %s', + position=11, + ), + direction=dict( + argstr='%s', + mandatory=True, + position=3, + ), + environ=dict( + nohash=True, + usedefault=True, + ), + fix_zeros_surf=dict( + argstr='-fix-zeros-surface', + position=13, + ), + fix_zeros_vol=dict( + argstr='-fix-zeros-volume', + position=12, + ), + in_file=dict( + argstr='%s', + mandatory=True, + position=0, + ), + left_corrected_areas=dict( + argstr='-left-corrected-areas %s', + position=6, + ), + left_surf=dict( + argstr='-left-surface %s', + mandatory=True, + position=5, + ), + merged_volume=dict( + argstr='-merged-volume', + position=14, + ), + out_file=dict( + argstr='%s', + keep_extension=True, + name_source=['in_file'], + name_template='smoothed_%s.nii', + position=4, + ), + right_corrected_areas=dict( + argstr='-right-corrected-areas %s', + position=8, + ), + right_surf=dict( + argstr='-right-surface %s', + mandatory=True, + position=7, + ), + sigma_surf=dict( + argstr='%s', + mandatory=True, + position=1, + ), + sigma_vol=dict( + argstr='%s', + mandatory=True, + position=2, + ), + ) + inputs = CiftiSmooth.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_CiftiSmooth_outputs(): + output_map = dict(out_file=dict(), ) + outputs = CiftiSmooth.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/testing/data/sub-01.L.midthickness.32k_fs_LR.surf.gii b/nipype/testing/data/sub-01.L.midthickness.32k_fs_LR.surf.gii new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nipype/testing/data/sub-01.R.midthickness.32k_fs_LR.surf.gii b/nipype/testing/data/sub-01.R.midthickness.32k_fs_LR.surf.gii new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nipype/testing/data/sub-01_task-rest.dtseries.nii b/nipype/testing/data/sub-01_task-rest.dtseries.nii new file mode 100644 index 0000000000..e69de29bb2 From efdbc711c9cbe22b5f03a01e9109512ed4d3f5fa Mon Sep 17 00:00:00 2001 From: mathiasg Date: Thu, 31 Jan 2019 16:52:56 -0500 Subject: [PATCH 2/2] sty: remove unused import --- nipype/interfaces/workbench/cifti.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nipype/interfaces/workbench/cifti.py b/nipype/interfaces/workbench/cifti.py index c7244c02c7..be4051e5b4 100644 --- a/nipype/interfaces/workbench/cifti.py +++ b/nipype/interfaces/workbench/cifti.py @@ -4,7 +4,6 @@ """This module provides interfaces for workbench CIFTI commands""" from __future__ import (print_function, division, unicode_literals, absolute_import) -import os from ..base import (TraitedSpec, File, traits, CommandLineInputSpec) from .base import WBCommand