Skip to content

Commit aeecd2f

Browse files
committed
Merge pull request #1435 from mgxd/master
[ENH] added interface for dcm2niix
2 parents 34c3b8b + 269ca84 commit aeecd2f

File tree

2 files changed

+152
-15
lines changed

2 files changed

+152
-15
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Release 0.12.0-rc1 (April 20, 2016)
22
============
33

4+
* ENH: Added dcm2niix interface (https://github.com/nipy/nipype/pull/1435)
45
* ENH: Add nipype_crash_search command (https://github.com/nipy/nipype/pull/1422)
56
* ENH: Created interface for BrainSuite Cortical Surface Extraction command line tools (https://github.com/nipy/nipype/pull/1305)
67
* FIX: job execution on systems/approaches where locale is undefined (https://github.com/nipy/nipype/pull/1401)

nipype/interfaces/dcm2nii.py

Lines changed: 151 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,35 @@ class Dcm2niiInputSpec(CommandLineInputSpec):
2323
copyfile=False, mandatory=True, xor=['source_dir'])
2424
source_dir = Directory(exists=True, argstr="%s", position=-1, mandatory=True,
2525
xor=['source_names'])
26-
anonymize = traits.Bool(True, argstr='-a', usedefault=True)
27-
config_file = File(exists=True, argstr="-b %s", genfile=True)
28-
collapse_folders = traits.Bool(True, argstr='-c', usedefault=True)
29-
date_in_filename = traits.Bool(True, argstr='-d', usedefault=True)
30-
events_in_filename = traits.Bool(True, argstr='-e', usedefault=True)
31-
source_in_filename = traits.Bool(False, argstr='-f', usedefault=True)
32-
gzip_output = traits.Bool(False, argstr='-g', usedefault=True)
33-
id_in_filename = traits.Bool(False, argstr='-i', usedefault=True)
34-
nii_output = traits.Bool(True, argstr='-n', usedefault=True)
35-
output_dir = Directory(exists=True, argstr='-o %s', genfile=True)
36-
protocol_in_filename = traits.Bool(True, argstr='-p', usedefault=True)
37-
reorient = traits.Bool(argstr='-r')
38-
spm_analyze = traits.Bool(argstr='-s', xor=['nii_output'])
39-
convert_all_pars = traits.Bool(True, argstr='-v', usedefault=True)
40-
reorient_and_crop = traits.Bool(False, argstr='-x', usedefault=True)
26+
anonymize = traits.Bool(True, argstr='-a', usedefault=True,
27+
desc="Remove identifying information")
28+
config_file = File(exists=True, argstr="-b %s", genfile=True,
29+
desc="Load settings from specified inifile")
30+
collapse_folders = traits.Bool(True, argstr='-c', usedefault=True,
31+
desc="Collapse input folders")
32+
date_in_filename = traits.Bool(True, argstr='-d', usedefault=True,
33+
desc="Date in filename")
34+
events_in_filename = traits.Bool(True, argstr='-e', usedefault=True,
35+
desc="Events (series/acq) in filename")
36+
source_in_filename = traits.Bool(False, argstr='-f', usedefault=True,
37+
desc="Source filename")
38+
gzip_output = traits.Bool(False, argstr='-g', usedefault=True,
39+
desc="Gzip output (.gz)")
40+
id_in_filename = traits.Bool(False, argstr='-i', usedefault=True,
41+
desc="ID in filename")
42+
nii_output = traits.Bool(True, argstr='-n', usedefault=True,
43+
desc="Save as .nii - if no, create .hdr/.img pair")
44+
output_dir = Directory(exists=True, argstr='-o %s', genfile=True,
45+
desc="Output dir - if unspecified, source directory is used")
46+
protocol_in_filename = traits.Bool(True, argstr='-p', usedefault=True,
47+
desc="Protocol in filename")
48+
reorient = traits.Bool(argstr='-r', desc="Reorient image to nearest orthogonal")
49+
spm_analyze = traits.Bool(argstr='-s', xor=['nii_output'],
50+
desc="SPM2/Analyze not SPM5/NIfTI")
51+
convert_all_pars = traits.Bool(True, argstr='-v', usedefault=True,
52+
desc="Convert every image in directory")
53+
reorient_and_crop = traits.Bool(False, argstr='-x', usedefault=True,
54+
desc="Reorient and crop 3D images")
4155

4256

4357
class Dcm2niiOutputSpec(TraitedSpec):
@@ -185,3 +199,125 @@ def _gen_filename(self, name):
185199
f.close()
186200
return config_file
187201
return None
202+
203+
204+
class Dcm2niixInputSpec(CommandLineInputSpec):
205+
source_names = InputMultiPath(File(exists=True), argstr="%s", position=-1,
206+
copyfile=False, mandatory=True, xor=['source_dir'])
207+
source_dir = Directory(exists=True, argstr="%s", position=-1, mandatory=True,
208+
xor=['source_names'])
209+
out_filename = traits.Str('%t%p', argstr="-f %s", usedefault=True,
210+
desc="Output filename")
211+
output_dir = Directory(exists=True, argstr='-o %s', genfile=True,
212+
desc="Output directory")
213+
bids_format = traits.Bool(True, argstr='-b', usedefault=True,
214+
desc="Create a BIDS sidecar file")
215+
compress = traits.Enum('i', ['y','i','n'], argstr='-z %s', usedefault=True,
216+
desc="Gzip compress images - [y=pigz, i=internal, n=no]")
217+
merge_imgs = traits.Bool(False, argstr='-m', usedefault=True,
218+
desc="merge 2D slices from same series")
219+
single_file = traits.Bool(False, argstr='-s', usedefault=True,
220+
desc="Convert only one image (filename as last input")
221+
verbose = traits.Bool(False, argstr='-v', usedefault=True,
222+
desc="Verbose output")
223+
224+
225+
class Dcm2niixOutputSpec(TraitedSpec):
226+
converted_files = OutputMultiPath(File(exists=True))
227+
bvecs = OutputMultiPath(File(exists=True))
228+
bvals = OutputMultiPath(File(exists=True))
229+
bids = OutputMultiPath(File(exists=True))
230+
231+
232+
class Dcm2niix(CommandLine):
233+
"""Uses Chris Rorden's dcm2niix to convert dicom files
234+
Examples
235+
========
236+
>>> from nipype.interfaces.dcm2nii import Dcm2niix
237+
>>> converter = Dcm2niix()
238+
>>> converter.inputs.source_names = ['functional_1.dcm', 'functional_2.dcm']
239+
>>> converter.inputs.compress = 'i'
240+
>>> converter.inputs.single_file = True
241+
>>> converter.inputs.output_dir = '.'
242+
>>> converter.cmdline
243+
'dcm2niix -b y -z i -m n -f %t%p -o . -s y -v n functional_1.dcm'
244+
"""
245+
246+
input_spec = Dcm2niixInputSpec
247+
output_spec = Dcm2niixOutputSpec
248+
_cmd = 'dcm2niix'
249+
250+
def _format_arg(self, opt, spec, val):
251+
if opt in ['bids_format', 'merge_imgs', 'single_file', 'verbose']:
252+
spec = deepcopy(spec)
253+
if val:
254+
spec.argstr += ' y'
255+
else:
256+
spec.argstr += ' n'
257+
val = True
258+
if opt == 'source_names':
259+
return spec.argstr % val[0]
260+
return super(Dcm2niix, self)._format_arg(opt, spec, val)
261+
262+
def _run_interface(self, runtime):
263+
new_runtime = super(Dcm2niix, self)._run_interface(runtime)
264+
if self.inputs.bids_format:
265+
(self.output_files, self.bvecs,
266+
self.bvals, self.bids) = self._parse_stdout(new_runtime.stdout)
267+
else:
268+
(self.output_files, self.bvecs,
269+
self.bvals) = self._parse_stdout(new_runtime.stdout)
270+
return new_runtime
271+
272+
def _parse_stdout(self, stdout):
273+
files = []
274+
bvecs = []
275+
bvals = []
276+
bids = []
277+
skip = False
278+
find_b = False
279+
for line in stdout.split("\n"):
280+
if not skip:
281+
out_file = None
282+
if line.startswith("Convert "): # output
283+
fname = str(re.search('\S+/\S+', line).group(0))
284+
if isdefined(self.inputs.output_dir):
285+
output_dir = self.inputs.output_dir
286+
else:
287+
output_dir = self._gen_filename('output_dir')
288+
out_file = os.path.abspath(os.path.join(output_dir, fname))
289+
# extract bvals
290+
if find_b:
291+
bvecs.append(out_file + ".bvec")
292+
bvals.append(out_file + ".bval")
293+
find_b = False
294+
# next scan will have bvals/bvecs
295+
elif 'DTI gradient directions' in line:
296+
find_b = True
297+
else:
298+
pass
299+
if out_file:
300+
files.append(out_file + ".nii.gz")
301+
if self.inputs.bids_format:
302+
bids.append(out_file + ".bids")
303+
continue
304+
skip = False
305+
# just return what was done
306+
if not bids:
307+
return files, bvecs, bvals
308+
else:
309+
return files, bvecs, bvals, bids
310+
311+
def _list_outputs(self):
312+
outputs = self.output_spec().get()
313+
outputs['converted_files'] = self.output_files
314+
outputs['bvecs'] = self.bvecs
315+
outputs['bvals'] = self.bvals
316+
if self.inputs.bids_format:
317+
outputs['bids'] = self.bids
318+
return outputs
319+
320+
def _gen_filename(self, name):
321+
if name == 'output_dir':
322+
return os.getcwd()
323+
return None

0 commit comments

Comments
 (0)