Skip to content

Commit 0f45bc9

Browse files
committed
Add dwi2tensor and dwi2fod
1 parent 9612ffe commit 0f45bc9

File tree

4 files changed

+338
-0
lines changed

4 files changed

+338
-0
lines changed

nipype/interfaces/mrtrix3/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
from utils import Mesh2PVE, Generate5tt
66
from preprocess import ResponseSD, ACTPrepareFSL
77
from tracking import Tractography
8+
from reconst import FitTensor, EstimateFOD

nipype/interfaces/mrtrix3/reconst.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
# -*- coding: utf-8 -*-
4+
5+
"""
6+
Change directory to provide relative paths for doctests
7+
>>> import os
8+
>>> filepath = os.path.dirname(os.path.realpath(__file__ ))
9+
>>> datadir = os.path.realpath(os.path.join(filepath,
10+
... '../../testing/data'))
11+
>>> os.chdir(datadir)
12+
13+
"""
14+
import os
15+
import os.path as op
16+
17+
from nipype.interfaces.base import (
18+
CommandLineInputSpec, CommandLine, traits, TraitedSpec, File,
19+
InputMultiPath)
20+
21+
from nipype.utils.filemanip import split_filename
22+
from nipype.interfaces.traits_extension import isdefined
23+
24+
class FitTensorInputSpec(CommandLineInputSpec):
25+
in_file = File(exists=True, argstr='%s', mandatory=True, position=-2,
26+
desc='input diffusion weighted images')
27+
out_file = File(
28+
'dti.mif', argstr='%s', mandatory=True, position=-1,
29+
usedefault=True, desc='the output diffusion tensor image')
30+
31+
# General options
32+
in_mask = File(exists=True, argstr='-mask %s',
33+
desc=('only perform computation within the specified binary '
34+
'brain mask image'))
35+
method = traits.Enum(
36+
'nonlinear', 'loglinear', 'sech', 'rician', argstr='-method %s',
37+
desc=('select method used to perform the fitting'))
38+
reg_term = traits.Float(
39+
5.e3, argstr='-regularisation %f',
40+
desc=('specify the strength of the regularisation term on the magnitude '
41+
'of the tensor elements (default = 5000). This only applies to the '
42+
'non-linear methods'))
43+
44+
45+
# DW gradient table import options
46+
grad_file = File(exists=True, argstr='-grad %s',
47+
desc='dw gradient scheme (MRTrix format')
48+
grad_fsl = traits.Tuple(
49+
File(exists=True), File(exists=True), argstr='-fslgrad %s %s',
50+
desc='(bvecs, bvals) dw gradient scheme (FSL format')
51+
bval_scale = traits.Enum(
52+
'yes', 'no', argstr='-bvalue_scaling %s',
53+
desc=('specifies whether the b - values should be scaled by the square'
54+
' of the corresponding DW gradient norm, as often required for '
55+
'multishell or DSI DW acquisition schemes. The default action '
56+
'can also be set in the MRtrix config file, under the '
57+
'BValueScaling entry. Valid choices are yes / no, true / '
58+
'false, 0 / 1 (default: true).'))
59+
60+
61+
class FitTensorOutputSpec(TraitedSpec):
62+
out_file = File(exists=True, desc='the output DTI file')
63+
64+
65+
class FitTensor(CommandLine):
66+
67+
"""
68+
Convert diffusion-weighted images to tensor images
69+
70+
71+
Example
72+
-------
73+
74+
>>> import nipype.interfaces.mrtrix3 as mrt
75+
>>> tsr = mrt.FitTensor()
76+
>>> tsr.inputs.in_file = 'dwi.mif'
77+
>>> tsr.inputs.in_mask = 'mask.nii.gz'
78+
>>> tsr.inputs.grad_fsl = ('bvecs', 'bvals')
79+
>>> tsr.cmdline # doctest: +ELLIPSIS
80+
'dwi2tensor -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif dti.mif'
81+
>>> tsr.run() # doctest: +SKIP
82+
"""
83+
84+
_cmd = 'dwi2tensor'
85+
input_spec = FitTensorInputSpec
86+
output_spec = FitTensorOutputSpec
87+
88+
def _list_outputs(self):
89+
outputs = self.output_spec().get()
90+
outputs['out_file'] = op.abspath(self.inputs.out_file)
91+
return outputs
92+
93+
94+
class EstimateFODInputSpec(CommandLineInputSpec):
95+
in_file = File(exists=True, argstr='%s', mandatory=True, position=-3,
96+
desc='input diffusion weighted images')
97+
response = File(
98+
exists=True, argstr='%s', mandatory=True, position=-2,
99+
desc=('a text file containing the diffusion-weighted signal response '
100+
'function coefficients for a single fibre population'))
101+
out_file = File(
102+
'fods.mif', argstr='%s', mandatory=True, position=-1,
103+
usedefault=True, desc='the output spherical harmonics coefficients image')
104+
105+
# DW gradient table import options
106+
grad_file = File(exists=True, argstr='-grad %s',
107+
desc='dw gradient scheme (MRTrix format')
108+
grad_fsl = traits.Tuple(
109+
File(exists=True), File(exists=True), argstr='-fslgrad %s %s',
110+
desc='(bvecs, bvals) dw gradient scheme (FSL format')
111+
bval_scale = traits.Enum(
112+
'yes', 'no', argstr='-bvalue_scaling %s',
113+
desc=('specifies whether the b - values should be scaled by the square'
114+
' of the corresponding DW gradient norm, as often required for '
115+
'multishell or DSI DW acquisition schemes. The default action '
116+
'can also be set in the MRtrix config file, under the '
117+
'BValueScaling entry. Valid choices are yes / no, true / '
118+
'false, 0 / 1 (default: true).'))
119+
120+
# DW Shell selection options
121+
shell = traits.List(traits.Float, sep=',', argstr='-shell %f',
122+
desc='specify one or more dw gradient shells')
123+
124+
# Spherical deconvolution options
125+
max_sh = traits.Int(8, argstr='-lmax %d',
126+
desc='maximum harmonic degree of response function')
127+
in_mask = File(exists=True, argstr='-mask %s',
128+
desc='provide initial mask image')
129+
in_dirs = File(
130+
exists=True, argstr='-directions %s',
131+
desc=('specify the directions over which to apply the non-negativity '
132+
'constraint (by default, the built-in 300 direction set is used). '
133+
'These should be supplied as a text file containing the [ az el ] '
134+
'pairs for the directions.'))
135+
sh_filter = File(
136+
exists=True, argstr='-filter %s',
137+
desc=('the linear frequency filtering parameters used for the initial '
138+
'linear spherical deconvolution step (default = [ 1 1 1 0 0 ]). '
139+
'These should be supplied as a text file containing the filtering '
140+
'coefficients for each even harmonic order.'))
141+
142+
neg_lambda = traits.Float(
143+
1.0, argstr='-neg_lambda %f',
144+
desc=('the regularisation parameter lambda that controls the strength of '
145+
'the non-negativity constraint'))
146+
thres = traits.Float(
147+
0.0, argstr='-threshold %f',
148+
desc=('the threshold below which the amplitude of the FOD is assumed to be '
149+
'zero, expressed as an absolute amplitude'))
150+
151+
n_iter = traits.Int(50, argstr='-niter %d', desc=('the maximum number of iterat'
152+
'ions to perform for each voxel'))
153+
154+
155+
class EstimateFODOutputSpec(TraitedSpec):
156+
out_file = File(exists=True, desc='the output response file')
157+
158+
159+
class EstimateFOD(CommandLine):
160+
161+
"""
162+
Convert diffusion-weighted images to tensor images
163+
164+
Note that this program makes use of implied symmetries in the diffusion
165+
profile. First, the fact the signal attenuation profile is real implies
166+
that it has conjugate symmetry, i.e. Y(l,-m) = Y(l,m)* (where * denotes
167+
the complex conjugate). Second, the diffusion profile should be
168+
antipodally symmetric (i.e. S(x) = S(-x)), implying that all odd l
169+
components should be zero. Therefore, this program only computes the even
170+
elements.
171+
172+
Note that the spherical harmonics equations used here differ slightly from
173+
those conventionally used, in that the (-1)^m factor has been omitted.
174+
This should be taken into account in all subsequent calculations.
175+
The spherical harmonic coefficients are stored as follows. First, since
176+
the signal attenuation profile is real, it has conjugate symmetry, i.e.
177+
Y(l,-m) = Y(l,m)* (where * denotes the complex conjugate). Second, the
178+
diffusion profile should be antipodally symmetric (i.e. S(x) = S(-x)),
179+
implying that all odd l components should be zero. Therefore, only the
180+
even elements are computed.
181+
182+
Note that the spherical harmonics equations used here differ slightly from
183+
those conventionally used, in that the (-1)^m factor has been omitted.
184+
This should be taken into account in all subsequent calculations.
185+
Each volume in the output image corresponds to a different spherical
186+
harmonic component. Each volume will correspond to the following:
187+
188+
volume 0: l = 0, m = 0
189+
volume 1: l = 2, m = -2 (imaginary part of m=2 SH)
190+
volume 2: l = 2, m = -1 (imaginary part of m=1 SH)
191+
volume 3: l = 2, m = 0
192+
volume 4: l = 2, m = 1 (real part of m=1 SH)
193+
volume 5: l = 2, m = 2 (real part of m=2 SH)
194+
etc...
195+
196+
197+
198+
Example
199+
-------
200+
201+
>>> import nipype.interfaces.mrtrix3 as mrt
202+
>>> fod = mrt.EstimateFOD()
203+
>>> fod.inputs.in_file = 'dwi.mif'
204+
>>> fod.inputs.in_mask = 'mask.nii.gz'
205+
>>> fod.inputs.grad_fsl = ('bvecs', 'bvals')
206+
>>> fod.cmdline # doctest: +ELLIPSIS
207+
'dwi2fod -fslgrad bvecs bvals -mask mask.nii.gz dwi.mif fods.mif'
208+
>>> fod.run() # doctest: +SKIP
209+
"""
210+
211+
_cmd = 'dwi2fod'
212+
input_spec = EstimateFODInputSpec
213+
output_spec = EstimateFODOutputSpec
214+
215+
def _list_outputs(self):
216+
outputs = self.output_spec().get()
217+
outputs['out_file'] = op.abspath(self.inputs.out_file)
218+
return outputs
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.mrtrix3.reconst import EstimateFOD
4+
5+
def test_EstimateFOD_inputs():
6+
input_map = dict(args=dict(argstr='%s',
7+
),
8+
bval_scale=dict(argstr='-bvalue_scaling %s',
9+
),
10+
environ=dict(nohash=True,
11+
usedefault=True,
12+
),
13+
grad_file=dict(argstr='-grad %s',
14+
),
15+
grad_fsl=dict(argstr='-fslgrad %s %s',
16+
),
17+
ignore_exception=dict(nohash=True,
18+
usedefault=True,
19+
),
20+
in_dirs=dict(argstr='-directions %s',
21+
),
22+
in_file=dict(argstr='%s',
23+
mandatory=True,
24+
position=-3,
25+
),
26+
in_mask=dict(argstr='-mask %s',
27+
),
28+
max_sh=dict(argstr='-lmax %d',
29+
),
30+
n_iter=dict(argstr='-niter %d',
31+
),
32+
neg_lambda=dict(argstr='-neg_lambda %f',
33+
),
34+
out_file=dict(argstr='%s',
35+
mandatory=True,
36+
position=-1,
37+
usedefault=True,
38+
),
39+
response=dict(argstr='%s',
40+
mandatory=True,
41+
position=-2,
42+
),
43+
sh_filter=dict(argstr='-filter %s',
44+
),
45+
shell=dict(argstr='-shell %f',
46+
sep=',',
47+
),
48+
terminal_output=dict(nohash=True,
49+
),
50+
thres=dict(argstr='-threshold %f',
51+
),
52+
)
53+
inputs = EstimateFOD.input_spec()
54+
55+
for key, metadata in input_map.items():
56+
for metakey, value in metadata.items():
57+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
58+
59+
def test_EstimateFOD_outputs():
60+
output_map = dict(out_file=dict(),
61+
)
62+
outputs = EstimateFOD.output_spec()
63+
64+
for key, metadata in output_map.items():
65+
for metakey, value in metadata.items():
66+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
67+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.mrtrix3.reconst import FitTensor
4+
5+
def test_FitTensor_inputs():
6+
input_map = dict(args=dict(argstr='%s',
7+
),
8+
bval_scale=dict(argstr='-bvalue_scaling %s',
9+
),
10+
environ=dict(nohash=True,
11+
usedefault=True,
12+
),
13+
grad_file=dict(argstr='-grad %s',
14+
),
15+
grad_fsl=dict(argstr='-fslgrad %s %s',
16+
),
17+
ignore_exception=dict(nohash=True,
18+
usedefault=True,
19+
),
20+
in_file=dict(argstr='%s',
21+
mandatory=True,
22+
position=-2,
23+
),
24+
in_mask=dict(argstr='-mask %s',
25+
),
26+
method=dict(argstr='-method %s',
27+
),
28+
out_file=dict(argstr='%s',
29+
mandatory=True,
30+
position=-1,
31+
usedefault=True,
32+
),
33+
reg_term=dict(argstr='-regularisation %f',
34+
),
35+
terminal_output=dict(nohash=True,
36+
),
37+
)
38+
inputs = FitTensor.input_spec()
39+
40+
for key, metadata in input_map.items():
41+
for metakey, value in metadata.items():
42+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
43+
44+
def test_FitTensor_outputs():
45+
output_map = dict(out_file=dict(),
46+
)
47+
outputs = FitTensor.output_spec()
48+
49+
for key, metadata in output_map.items():
50+
for metakey, value in metadata.items():
51+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
52+

0 commit comments

Comments
 (0)