Skip to content

[ENH] added interface for dcm2niix #1435

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 25 commits into from
Apr 27, 2016
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
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Release 0.12.0-rc1 (April 20, 2016)
============

* ENH: Added dcm2niix interface (https://github.com/nipy/nipype/pull/1435)
* ENH: Add nipype_crash_search command (https://github.com/nipy/nipype/pull/1422)
* ENH: Created interface for BrainSuite Cortical Surface Extraction command line tools (https://github.com/nipy/nipype/pull/1305)
* FIX: job execution on systems/approaches where locale is undefined (https://github.com/nipy/nipype/pull/1401)
Expand Down
166 changes: 151 additions & 15 deletions nipype/interfaces/dcm2nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,35 @@ class Dcm2niiInputSpec(CommandLineInputSpec):
copyfile=False, mandatory=True, xor=['source_dir'])
source_dir = Directory(exists=True, argstr="%s", position=-1, mandatory=True,
xor=['source_names'])
anonymize = traits.Bool(True, argstr='-a', usedefault=True)
config_file = File(exists=True, argstr="-b %s", genfile=True)
collapse_folders = traits.Bool(True, argstr='-c', usedefault=True)
date_in_filename = traits.Bool(True, argstr='-d', usedefault=True)
events_in_filename = traits.Bool(True, argstr='-e', usedefault=True)
source_in_filename = traits.Bool(False, argstr='-f', usedefault=True)
gzip_output = traits.Bool(False, argstr='-g', usedefault=True)
id_in_filename = traits.Bool(False, argstr='-i', usedefault=True)
nii_output = traits.Bool(True, argstr='-n', usedefault=True)
output_dir = Directory(exists=True, argstr='-o %s', genfile=True)
protocol_in_filename = traits.Bool(True, argstr='-p', usedefault=True)
reorient = traits.Bool(argstr='-r')
spm_analyze = traits.Bool(argstr='-s', xor=['nii_output'])
convert_all_pars = traits.Bool(True, argstr='-v', usedefault=True)
reorient_and_crop = traits.Bool(False, argstr='-x', usedefault=True)
anonymize = traits.Bool(True, argstr='-a', usedefault=True,
desc="Remove identifying information")
config_file = File(exists=True, argstr="-b %s", genfile=True,
desc="Load settings from specified inifile")
collapse_folders = traits.Bool(True, argstr='-c', usedefault=True,
desc="Collapse input folders")
date_in_filename = traits.Bool(True, argstr='-d', usedefault=True,
desc="Date in filename")
events_in_filename = traits.Bool(True, argstr='-e', usedefault=True,
desc="Events (series/acq) in filename")
source_in_filename = traits.Bool(False, argstr='-f', usedefault=True,
desc="Source filename")
gzip_output = traits.Bool(False, argstr='-g', usedefault=True,
desc="Gzip output (.gz)")
id_in_filename = traits.Bool(False, argstr='-i', usedefault=True,
desc="ID in filename")
nii_output = traits.Bool(True, argstr='-n', usedefault=True,
desc="Save as .nii - if no, create .hdr/.img pair")
output_dir = Directory(exists=True, argstr='-o %s', genfile=True,
desc="Output dir - if unspecified, source directory is used")
protocol_in_filename = traits.Bool(True, argstr='-p', usedefault=True,
desc="Protocol in filename")
reorient = traits.Bool(argstr='-r', desc="Reorient image to nearest orthogonal")
spm_analyze = traits.Bool(argstr='-s', xor=['nii_output'],
desc="SPM2/Analyze not SPM5/NIfTI")
convert_all_pars = traits.Bool(True, argstr='-v', usedefault=True,
desc="Convert every image in directory")
reorient_and_crop = traits.Bool(False, argstr='-x', usedefault=True,
desc="Reorient and crop 3D images")


class Dcm2niiOutputSpec(TraitedSpec):
Expand Down Expand Up @@ -185,3 +199,125 @@ def _gen_filename(self, name):
f.close()
return config_file
return None


class Dcm2niixInputSpec(CommandLineInputSpec):
source_names = InputMultiPath(File(exists=True), argstr="%s", position=-1,
copyfile=False, mandatory=True, xor=['source_dir'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

desc missing for all inputs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know dcm2nii didn't have any either. but that should be fixed as well.

source_dir = Directory(exists=True, argstr="%s", position=-1, mandatory=True,
xor=['source_names'])
out_filename = traits.Str('%t%p', argstr="-f %s", usedefault=True,
desc="Output filename")
output_dir = Directory(exists=True, argstr='-o %s', genfile=True,
desc="Output directory")
bids_format = traits.Bool(True, argstr='-b', usedefault=True,
desc="Create a BIDS sidecar file")
compress = traits.Enum('i', ['y','i','n'], argstr='-z %s', usedefault=True,
desc="Gzip compress images - [y=pigz, i=internal, n=no]")
merge_imgs = traits.Bool(False, argstr='-m', usedefault=True,
desc="merge 2D slices from same series")
single_file = traits.Bool(False, argstr='-s', usedefault=True,
desc="Convert only one image (filename as last input")
verbose = traits.Bool(False, argstr='-v', usedefault=True,
desc="Verbose output")


class Dcm2niixOutputSpec(TraitedSpec):
converted_files = OutputMultiPath(File(exists=True))
bvecs = OutputMultiPath(File(exists=True))
bvals = OutputMultiPath(File(exists=True))
bids = OutputMultiPath(File(exists=True))


class Dcm2niix(CommandLine):
"""Uses Chris Rorden's dcm2niix to convert dicom files
Examples
========
>>> from nipype.interfaces.dcm2nii import Dcm2niix
>>> converter = Dcm2niix()
>>> converter.inputs.source_names = ['functional_1.dcm', 'functional_2.dcm']
>>> converter.inputs.compress = 'i'
>>> converter.inputs.single_file = True
>>> converter.inputs.output_dir = '.'
>>> converter.cmdline
'dcm2niix -b y -z i -m n -f %t%p -o . -s y -v n functional_1.dcm'
"""

input_spec = Dcm2niixInputSpec
output_spec = Dcm2niixOutputSpec
_cmd = 'dcm2niix'

def _format_arg(self, opt, spec, val):
if opt in ['bids_format', 'merge_imgs', 'single_file', 'verbose']:
spec = deepcopy(spec)
if val:
spec.argstr += ' y'
else:
spec.argstr += ' n'
val = True
if opt == 'source_names':
return spec.argstr % val[0]
return super(Dcm2niix, self)._format_arg(opt, spec, val)

def _run_interface(self, runtime):
new_runtime = super(Dcm2niix, self)._run_interface(runtime)
if self.inputs.bids_format:
(self.output_files, self.bvecs,
self.bvals, self.bids) = self._parse_stdout(new_runtime.stdout)
else:
(self.output_files, self.bvecs,
self.bvals) = self._parse_stdout(new_runtime.stdout)
return new_runtime

def _parse_stdout(self, stdout):
files = []
bvecs = []
bvals = []
bids = []
skip = False
find_b = False
for line in stdout.split("\n"):
if not skip:
out_file = None
if line.startswith("Convert "): # output
fname = str(re.search('\S+/\S+', line).group(0))
if isdefined(self.inputs.output_dir):
output_dir = self.inputs.output_dir
else:
output_dir = self._gen_filename('output_dir')
out_file = os.path.abspath(os.path.join(output_dir, fname))
# extract bvals
if find_b:
bvecs.append(out_file + ".bvec")
bvals.append(out_file + ".bval")
find_b = False
# next scan will have bvals/bvecs
elif 'DTI gradient directions' in line:
find_b = True
else:
pass
if out_file:
files.append(out_file + ".nii.gz")
if self.inputs.bids_format:
bids.append(out_file + ".bids")
continue
skip = False
# just return what was done
if not bids:
return files, bvecs, bvals
else:
return files, bvecs, bvals, bids

def _list_outputs(self):
outputs = self.output_spec().get()
outputs['converted_files'] = self.output_files
outputs['bvecs'] = self.bvecs
outputs['bvals'] = self.bvals
if self.inputs.bids_format:
outputs['bids'] = self.bids
return outputs

def _gen_filename(self, name):
if name == 'output_dir':
return os.getcwd()
return None