Skip to content

Commit 4f49bf4

Browse files
committed
enh: add c3d and c4d interface
1 parent 168dfee commit 4f49bf4

File tree

1 file changed

+131
-1
lines changed

1 file changed

+131
-1
lines changed

nipype/interfaces/c3.py

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@
1010
"""
1111
from __future__ import (print_function, division, unicode_literals,
1212
absolute_import)
13+
import os
14+
from glob import glob
1315

1416
from .base import (CommandLineInputSpec, traits, TraitedSpec, File,
15-
SEMLikeCommandLine)
17+
SEMLikeCommandLine, InputMultiPath, OutputMultiPath,
18+
CommandLine, isdefined)
19+
from ..utils.filemanip import split_filename
20+
from .. import logging
21+
22+
iflogger = logging.getLogger("interface")
1623

1724

1825
class C3dAffineToolInputSpec(CommandLineInputSpec):
@@ -52,3 +59,126 @@ class C3dAffineTool(SEMLikeCommandLine):
5259

5360
_cmd = 'c3d_affine_tool'
5461
_outputs_filenames = {'itk_transform': 'affine.txt'}
62+
63+
64+
class C3dInputSpec(CommandLineInputSpec):
65+
in_file = InputMultiPath(File(),
66+
position=1,
67+
argstr="%s",
68+
mandatory=True,
69+
desc="Input file (wildcard and multiple are supported)")
70+
out_file = File(exists=False,
71+
argstr="-o %s",
72+
position=-1,
73+
xor=["out_files"],
74+
desc="Output file of last image on the stack")
75+
out_files = InputMultiPath(File(),
76+
argstr="-oo %s",
77+
xor=["out_file"],
78+
position=-1,
79+
desc=("Write all images on the convert3d stack as multiple files."
80+
" Supports both list of output files or a pattern for the output"
81+
" filenames (using %d substituion)."))
82+
pix_type = traits.Enum("float", "char", "uchar", "short", "ushort", "int", "uint", "double",
83+
argstr="-type %s",
84+
desc=("Specifies the pixel type for the output image. By default, images are written in"
85+
" floating point (float) format"))
86+
scale = traits.Either(traits.Int(), traits.Float(),
87+
argstr="-scale %s",
88+
desc="Multiplies the intensity of each voxel in the last image on the stack by the given factor.")
89+
shift = traits.Either(traits.Int(), traits.Float(),
90+
argstr="-shift %s",
91+
desc='Adds the given constant to every voxel.')
92+
interp = traits.Enum("Linear", "NearestNeighbor", "Cubic", "Sinc", "Gaussian",
93+
argstr="-interpolation %s",
94+
desc="Specifies the interpolation used with -resample and other commands. Default is Linear.")
95+
resample = traits.Str(argstr="-resample %s",
96+
desc=("Resamples the image, keeping the bounding box the same, but changing the number of"
97+
" voxels in the image. The dimensions can be specified as a percentage, for example to"
98+
" double the number of voxels in each direction. The -interpolation flag affects how"
99+
" sampling is performed."))
100+
smooth = traits.Str(argstr="-smooth %s",
101+
desc=("Applies Gaussian smoothing to the image. The parameter vector specifies the"
102+
" standard deviation of the Gaussian kernel."))
103+
multicomp_split = traits.Bool(False,
104+
usedefault=True,
105+
argstr="-mcr",
106+
position=0,
107+
desc="Enable reading of multi-component images.")
108+
is_4d = traits.Bool(False,
109+
usedefault=True,
110+
desc="Changes command to support 4D file operations (default is false).")
111+
112+
class C3dOutputSpec(TraitedSpec):
113+
out_files = OutputMultiPath(File(exists=False))
114+
115+
class C3d(CommandLine):
116+
"""
117+
Convert3d is a command-line tool for converting 3D (or 4D) images between common
118+
file formats. The tool also includes a growing list of commands for image manipulation,
119+
such as thresholding and resampling. The tool can also be used to obtain information about
120+
image files. More information on Convert3d can be found at:
121+
https://sourceforge.net/p/c3d/git/ci/master/tree/doc/c3d.md
122+
123+
124+
Example
125+
=======
126+
127+
>>> from nipype.interfaces.c3 import C3d
128+
>>> c3 = C3d()
129+
>>> c3.inputs.in_file = "T1.nii"
130+
>>> c3.inputs.pix_type = "short"
131+
>>> c3.inputs.out_file = "T1.img"
132+
>>> c3.cmdline
133+
'c3d T1.nii -type short -o T1.img'
134+
>>> c3.inputs.is_4d = True
135+
>>> c3.inputs.in_file = "epi.nii"
136+
>>> c3.inputs.out_file = "epi.img"
137+
>>> c3.cmdline
138+
'c4d epi.nii -type short -o epi.img'
139+
"""
140+
input_spec = C3dInputSpec
141+
output_spec = C3dOutputSpec
142+
143+
_cmd = "c3d"
144+
145+
def __init__(self, **inputs):
146+
super(C3d, self).__init__(**inputs)
147+
self.inputs.on_trait_change(self._is_4d, "is_4d")
148+
if self.inputs.is_4d:
149+
self._is_4d()
150+
151+
def _is_4d(self):
152+
self._cmd = "c4d" if self.inputs.is_4d else "c3d"
153+
154+
def _run_interface(self, runtime):
155+
cmd = self._cmd
156+
# by default, does not want to override file, so we define a new output file
157+
if not isdefined(self.inputs.out_file) and not isdefined(self.inputs.out_files):
158+
self._gen_outfile()
159+
runtime = super(C3d, self)._run_interface(runtime)
160+
self._cmd = cmd
161+
return runtime
162+
163+
def _gen_outfile(self):
164+
# if many infiles, raise exception
165+
if (len(self.inputs.in_file) > 1) or ("*" in self.inputs.in_file[0]):
166+
raise AttributeError("Multiple in_files found - specify either out_file or out_files")
167+
_, fn, ext = split_filename(self.inputs.in_file[0])
168+
self.inputs.out_file = fn + "_generated" + ext
169+
assert not os.path.exists(os.path.abspath(self.inputs.out_file))
170+
iflogger.info("Generating out_file to avoid overwriting")
171+
172+
def _list_outputs(self):
173+
outputs = self.output_spec().get()
174+
if isdefined(self.inputs.out_file):
175+
outputs["out_files"] = os.path.abspath(self.inputs.out_file)
176+
if isdefined(self.inputs.out_files):
177+
if not len(self.inputs.out_files) > 1:
178+
_out_files = glob(os.path.abspath(self.inputs.out_files[0]))
179+
else:
180+
_out_files = [os.path.abspath(fl) for fl in self.inputs.out_files
181+
if os.path.exists(os.path.abspath(fl))]
182+
outputs["out_files"] = _out_files
183+
184+
return outputs

0 commit comments

Comments
 (0)