Skip to content

RF: dcm2niix interface #2936

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 1 commit into from
Sep 19, 2019
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
3 changes: 2 additions & 1 deletion docker/generate_dockerfiles.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ function generate_base_dockerfile() {
--spm12 version=r7219 \
--env 'LD_LIBRARY_PATH=/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH' \
--freesurfer version=6.0.0-min \
--dcm2niix version=v1.0.20190902 method=source \
--run 'echo "cHJpbnRmICJrcnp5c3p0b2YuZ29yZ29sZXdza2lAZ21haWwuY29tCjUxNzIKICpDdnVtdkVWM3pUZmcKRlM1Si8yYzFhZ2c0RQoiID4gL29wdC9mcmVlc3VyZmVyLTYuMC4wLW1pbi9saWNlbnNlLnR4dA==" | base64 -d | sh' \
--install afni ants apt-utils bzip2 convert3d file fsl-core \
fsl-mni152-templates fusefat g++ git graphviz make python ruby \
unzip xvfb \
unzip xvfb git-annex-standalone liblzma-dev \
--add-to-entrypoint "source /etc/fsl/fsl.sh && source /etc/afni/afni.sh" \
--env ANTSPATH='/usr/lib/ants' \
PATH='/usr/lib/ants:$PATH' \
Expand Down
1 change: 1 addition & 0 deletions nipype/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def get_nipype_gitversion():
]

EXTRA_REQUIRES = {
'data': ['datalad'],
'doc': ['Sphinx>=1.4', 'numpydoc', 'matplotlib', 'pydotplus', 'pydot>=1.2.3'],
'duecredit': ['duecredit'],
'nipy': ['nitime', 'nilearn<0.5.0', 'dipy', 'nipy', 'matplotlib'],
Expand Down
90 changes: 50 additions & 40 deletions nipype/interfaces/dcm2nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import os
import re
from copy import deepcopy
import itertools as it
from glob import iglob

from ..utils.filemanip import split_filename
from .base import (CommandLine, CommandLineInputSpec, InputMultiPath, traits,
Expand Down Expand Up @@ -328,7 +330,7 @@ class Dcm2niixInputSpec(CommandLineInputSpec):
False,
argstr='-t',
usedefault=True,
desc="Flag if text notes include private patient details")
desc="Text notes including private patient details")
compression = traits.Enum(
1, 2, 3, 4, 5, 6, 7, 8, 9,
argstr='-%d',
Expand All @@ -346,6 +348,9 @@ class Dcm2niixInputSpec(CommandLineInputSpec):
philips_float = traits.Bool(
argstr='-p',
desc="Philips precise float (not display) scaling")
to_nrrd = traits.Bool(
argstr="-e",
desc="Export as NRRD instead of NIfTI")


class Dcm2niixOutputSpec(TraitedSpec):
Expand Down Expand Up @@ -393,8 +398,11 @@ def version(self):
return Info.version()

def _format_arg(self, opt, spec, val):
bools = ['bids_format', 'merge_imgs', 'single_file', 'verbose', 'crop',
'has_private', 'anon_bids', 'ignore_deriv', 'philips_float']
bools = [
'bids_format', 'merge_imgs', 'single_file', 'verbose', 'crop',
'has_private', 'anon_bids', 'ignore_deriv', 'philips_float',
'to_nrrd',
]
if opt in bools:
spec = deepcopy(spec)
if val:
Expand All @@ -410,52 +418,54 @@ def _run_interface(self, runtime):
# may use return code 1 despite conversion
runtime = super(Dcm2niix, self)._run_interface(
runtime, correct_return_codes=(0, 1, ))
if self.inputs.bids_format:
(self.output_files, self.bvecs, self.bvals,
self.bids) = self._parse_stdout(runtime.stdout)
else:
(self.output_files, self.bvecs, self.bvals) = self._parse_stdout(
runtime.stdout)
self._parse_files(self._parse_stdout(runtime.stdout))
return runtime

def _parse_stdout(self, stdout):
files = []
bvecs = []
bvals = []
bids = []
skip = False
find_b = False
filenames = []
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))
out_file = os.path.abspath(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 gradients' in line or 'DTI gradient directions' in line or 'DTI vectors' in line:
find_b = True
if out_file:
ext = '.nii' if self.inputs.compress == 'n' else '.nii.gz'
files.append(out_file + ext)
if self.inputs.bids_format:
bids.append(out_file + ".json")
skip = False
# just return what was done
if not bids:
return files, bvecs, bvals
if line.startswith("Convert "): # output
fname = str(re.search(r'\S+/\S+', line).group(0))
filenames.append(os.path.abspath(fname))
return filenames

def _parse_files(self, filenames):
outfiles, bvals, bvecs, bids = [], [], [], []
outtypes = [".bval", ".bvec", ".json", ".txt"]
if self.inputs.to_nrrd:
outtypes += [".nrrd", ".nhdr", ".raw.gz"]
else:
return files, bvecs, bvals, bids
outtypes += [".nii", ".nii.gz"]

for filename in filenames:
# search for relevant files, and sort accordingly
for fl in search_files(filename, outtypes):
if (
fl.endswith(".nii") or
fl.endswith(".gz") or
fl.endswith(".nrrd") or
fl.endswith(".nhdr")
):
outfiles.append(fl)
elif fl.endswith(".bval"):
bvals.append(fl)
elif fl.endswith(".bvec"):
bvecs.append(fl)
elif fl.endswith(".json") or fl.endswith(".txt"):
bids.append(fl)
self.output_files = outfiles
self.bvecs = bvecs
self.bvals = bvals
self.bids = 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
outputs['bids'] = self.bids
return outputs

# https://stackoverflow.com/a/4829130
def search_files(prefix, outtypes):
return it.chain.from_iterable(iglob(prefix + outtype) for outtype in outtypes)
1 change: 1 addition & 0 deletions nipype/interfaces/tests/test_auto_Dcm2niix.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def test_Dcm2niix_inputs():
position=-1,
xor=['source_dir'],
),
to_nrrd=dict(argstr='-e', ),
verbose=dict(
argstr='-v',
usedefault=True,
Expand Down
8 changes: 3 additions & 5 deletions nipype/interfaces/tests/test_extra_dcm2nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,15 @@ def assert_dwi(eg, bids):
# ensure all outputs are of equal lengths
assert len(set(map(len, outputs))) == 1
else:
assert not eg2.outputs.bids
assert not eg.outputs.bids

dcm = Dcm2niix()
dcm.inputs.source_dir = datadir
dcm.inputs.out_filename = '%u%z'
eg1 = dcm.run()
assert_dwi(eg1, True)
assert_dwi(dcm.run(), True)

# now run specifying output directory and removing BIDS option
outdir = tmpdir.mkdir('conversion').strpath
dcm.inputs.output_dir = outdir
dcm.inputs.bids_format = False
eg2 = dcm.run()
assert_dwi(eg2, False)
assert_dwi(dcm.run(), False)