Skip to content

enh: c3d + c4d interface #2430

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 155 additions & 1 deletion nipype/interfaces/c3.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@
"""
from __future__ import (print_function, division, unicode_literals,
absolute_import)
import os
from glob import glob

from .base import (CommandLineInputSpec, traits, TraitedSpec, File,
SEMLikeCommandLine)
SEMLikeCommandLine, InputMultiPath, OutputMultiPath,
CommandLine, isdefined)
from ..utils.filemanip import split_filename
from .. import logging

iflogger = logging.getLogger("interface")


class C3dAffineToolInputSpec(CommandLineInputSpec):
Expand Down Expand Up @@ -52,3 +59,150 @@ class C3dAffineTool(SEMLikeCommandLine):

_cmd = 'c3d_affine_tool'
_outputs_filenames = {'itk_transform': 'affine.txt'}


class C3dInputSpec(CommandLineInputSpec):
in_file = InputMultiPath(
File(),
position=1,
argstr="%s",
mandatory=True,
desc="Input file (wildcard and multiple are supported).")
out_file = File(
exists=False,
argstr="-o %s",
position=-1,
xor=["out_files"],
desc="Output file of last image on the stack.")
out_files = InputMultiPath(
File(),
argstr="-oo %s",
xor=["out_file"],
position=-1,
desc=("Write all images on the convert3d stack as multiple files."
" Supports both list of output files or a pattern for the output"
" filenames (using %d substituion)."))
pix_type = traits.Enum(
"float", "char", "uchar", "short", "ushort", "int", "uint", "double",
argstr="-type %s",
desc=("Specifies the pixel type for the output image. By default,"
" images are written in floating point (float) format"))
scale = traits.Either(
traits.Int(), traits.Float(),
argstr="-scale %s",
desc=("Multiplies the intensity of each voxel in the last image on the"
" stack by the given factor."))
shift = traits.Either(
traits.Int(), traits.Float(),
argstr="-shift %s",
desc='Adds the given constant to every voxel.')
interp = traits.Enum(
"Linear", "NearestNeighbor", "Cubic", "Sinc", "Gaussian",
argstr="-interpolation %s",
desc=("Specifies the interpolation used with -resample and other"
" commands. Default is Linear."))
resample = traits.Str(
argstr="-resample %s",
desc=("Resamples the image, keeping the bounding box the same, but"
" changing the number of voxels in the image. The dimensions can be"
" specified as a percentage, for example to double the number of voxels"
" in each direction. The -interpolation flag affects how sampling is"
" performed."))
smooth = traits.Str(
argstr="-smooth %s",
desc=("Applies Gaussian smoothing to the image. The parameter vector"
" specifies the standard deviation of the Gaussian kernel."))
multicomp_split = traits.Bool(
False,
usedefault=True,
argstr="-mcr",
position=0,
desc="Enable reading of multi-component images.")
is_4d = traits.Bool(
False,
usedefault=True,
desc=("Changes command to support 4D file operations (default is"
" false)."))


class C3dOutputSpec(TraitedSpec):
out_files = OutputMultiPath(File(exists=False))


class C3d(CommandLine):
"""
Convert3d is a command-line tool for converting 3D (or 4D) images between
common file formats. The tool also includes a growing list of commands for
image manipulation, such as thresholding and resampling. The tool can also
be used to obtain information about image files. More information on
Convert3d can be found at:
https://sourceforge.net/p/c3d/git/ci/master/tree/doc/c3d.md


Example
=======

>>> from nipype.interfaces.c3 import C3d
>>> c3 = C3d()
>>> c3.inputs.in_file = "T1.nii"
>>> c3.inputs.pix_type = "short"
>>> c3.inputs.out_file = "T1.img"
>>> c3.cmdline
'c3d T1.nii -type short -o T1.img'
>>> c3.inputs.is_4d = True
>>> c3.inputs.in_file = "epi.nii"
>>> c3.inputs.out_file = "epi.img"
>>> c3.cmdline
'c4d epi.nii -type short -o epi.img'
"""
input_spec = C3dInputSpec
output_spec = C3dOutputSpec

_cmd = "c3d"

def __init__(self, **inputs):
super(C3d, self).__init__(**inputs)
self.inputs.on_trait_change(self._is_4d, "is_4d")
if self.inputs.is_4d:
self._is_4d()

def _is_4d(self):
self._cmd = "c4d" if self.inputs.is_4d else "c3d"

def _run_interface(self, runtime):
cmd = self._cmd
if (not isdefined(self.inputs.out_file)
and not isdefined(self.inputs.out_files)):
# Convert3d does not want to override file, by default
# so we define a new output file
self._gen_outfile()
runtime = super(C3d, self)._run_interface(runtime)
self._cmd = cmd
return runtime

def _gen_outfile(self):
# if many infiles, raise exception
if (len(self.inputs.in_file) > 1) or ("*" in self.inputs.in_file[0]):
raise AttributeError("Multiple in_files found - specify either"
" `out_file` or `out_files`.")
_, fn, ext = split_filename(self.inputs.in_file[0])
self.inputs.out_file = fn + "_generated" + ext
# if generated file will overwrite, raise error
if os.path.exists(os.path.abspath(self.inputs.out_file)):
raise IOError("File already found - to overwrite, use `out_file`.")
iflogger.info("Generating `out_file`.")

def _list_outputs(self):
outputs = self.output_spec().get()
if isdefined(self.inputs.out_file):
outputs["out_files"] = os.path.abspath(self.inputs.out_file)
if isdefined(self.inputs.out_files):
if len(self.inputs.out_files) == 1:
_out_files = glob(os.path.abspath(self.inputs.out_files[0]))
else:
_out_files = [os.path.abspath(f) for f in self.inputs.out_files
if os.path.exists(os.path.abspath(f))]
outputs["out_files"] = _out_files

return outputs

61 changes: 61 additions & 0 deletions nipype/interfaces/tests/test_auto_C3d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
from __future__ import unicode_literals
from ..c3 import C3d


def test_C3d_inputs():
input_map = dict(
args=dict(argstr='%s', ),
environ=dict(
nohash=True,
usedefault=True,
),
ignore_exception=dict(
deprecated='1.0.0',
nohash=True,
usedefault=True,
),
in_file=dict(
argstr='%s',
mandatory=True,
position=1,
),
interp=dict(argstr='-interpolation %s', ),
is_4d=dict(usedefault=True, ),
multicomp_split=dict(
argstr='-mcr',
position=0,
usedefault=True,
),
out_file=dict(
argstr='-o %s',
position=-1,
xor=['out_files'],
),
out_files=dict(
argstr='-oo %s',
position=-1,
xor=['out_file'],
),
pix_type=dict(argstr='-type %s', ),
resample=dict(argstr='-resample %s', ),
scale=dict(argstr='-scale %s', ),
shift=dict(argstr='-shift %s', ),
smooth=dict(argstr='-smooth %s', ),
terminal_output=dict(
deprecated='1.0.0',
nohash=True,
),
)
inputs = C3d.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_C3d_outputs():
output_map = dict(out_files=dict(), )
outputs = C3d.output_spec()

for key, metadata in list(output_map.items()):
for metakey, value in list(metadata.items()):
assert getattr(outputs.traits()[key], metakey) == value