7
7
"""
8
8
9
9
from nipype .interfaces .base import (
10
- TraitedSpec , BaseInterface , BaseInterfaceInputSpec , File )
10
+ TraitedSpec , BaseInterface , BaseInterfaceInputSpec , File ,
11
+ InputMultiPath , isdefined )
11
12
from nipype .utils .filemanip import split_filename
12
13
import os .path as op
13
14
import nibabel as nb
27
28
import numpy as np
28
29
from dipy .sims .voxel import (multi_tensor ,
29
30
all_tensor_evecs )
31
+ from dipy .core .gradients import GradientTable
30
32
31
33
32
34
class SimulateMultiTensorInputSpec (BaseInterfaceInputSpec ):
33
- fibers = InputMultiPath (File (exists = True ), mandatory = True ,
34
- desc = 'list of fibers principal directions' )
35
- vfractions = File (exists = True , mandatory = True ,
36
- desc = 'volume fractions' )
35
+ in_dirs = InputMultiPath (File (exists = True ), mandatory = True ,
36
+ desc = 'list of fibers (principal directions)' )
37
+ in_frac = InputMultiPath (File (exists = True ), mandatory = True ,
38
+ desc = ('volume fraction of each fiber' ))
39
+ in_vfms = InputMultiPath (File (exists = True ), mandatory = True ,
40
+ desc = 'volume fraction map' )
41
+ in_mask = File (exists = True , desc = 'mask to simulate data' )
42
+
37
43
baseline = File (exists = True , mandatory = True , desc = 'baseline T2 signal' )
38
44
gradients = File (exists = True , desc = 'gradients file' )
39
- bvec = File (exists = True , desc = 'bvecs file' )
40
- bval = File (exists = True , desc = 'bvals file' )
45
+ bvec = File (exists = True , mandatory = True , desc = 'bvecs file' )
46
+ bval = File (exists = True , mandatory = True , desc = 'bvals file' )
41
47
out_file = File ('sim_dwi.nii.gz' , usedefault = True ,
42
48
desc = 'output file with fractions to be simluated' )
49
+ out_mask = File ('sim_msk.nii.gz' , usedefault = True ,
50
+ desc = 'file with the mask simulated' )
43
51
44
52
45
53
class SimulateMultiTensorOutputSpec (TraitedSpec ):
46
- out_file = File (exists = True )
54
+ out_file = File (exists = True , desc = 'simulated DWIs' )
55
+ out_mask = File (exists = True , desc = 'mask file' )
47
56
48
57
49
58
class SimulateMultiTensor (BaseInterface ):
@@ -57,8 +66,8 @@ class SimulateMultiTensor(BaseInterface):
57
66
58
67
>>> import nipype.interfaces.dipy as dipy
59
68
>>> sim = dipy.SimulateMultiTensor()
60
- >>> sim.inputs.fibers = 'fibers.nii'
61
- >>> sim.inputs.vfractions = 'fractions.nii'
69
+ >>> sim.inputs.in_dirs = 'fibers.nii'
70
+ >>> sim.inputs.in_frac = 'fractions.nii'
62
71
>>> sim.inputs.baseline = 'S0.nii'
63
72
>>> sim.inputs.bvecs = 'bvecs'
64
73
>>> sim.inputs.bvals = 'bvals'
@@ -68,19 +77,84 @@ class SimulateMultiTensor(BaseInterface):
68
77
output_spec = SimulateMultiTensorOutputSpec
69
78
70
79
def _run_interface (self , runtime ):
71
- # Load the 4D image files
72
- img = nb .load (self .inputs .fibers )
73
- fibers = img .get_data ()
74
- fractions = nb .load (self .inputs .vfractions ).get_data ()
75
- affine = img .get_affine ()
76
-
77
80
# Load the baseline b0 signal
78
- b0 = nb .load (self .inputs .baseline ).get_data ()
81
+ b0_im = nb .load (self .inputs .baseline )
82
+ hdr = b0_im .get_header ()
83
+ shape = b0_im .get_shape ()
84
+ aff = b0_im .get_affine ()
85
+ b0 = b0_im .get_data ().reshape (- 1 )
86
+
87
+ ffsim = nb .concat_images ([nb .load (f ) for f in self .inputs .in_frac ])
88
+ ffs = np .squeeze (ffsim .get_data ()) # fiber fractions
89
+
90
+ vfsim = nb .concat_images ([nb .load (f ) for f in self .inputs .in_vfms ])
91
+ vfs = np .squeeze (vfsim .get_data ()) # volume fractions
92
+
93
+ # Load structural files
94
+ thetas = []
95
+ phis = []
96
+
97
+ total_ff = np .sum (ffs , axis = 3 )
98
+ total_vf = np .sum (vfs , axis = 3 )
99
+
100
+ msk = np .zeros (shape , dtype = np .uint8 )
101
+ msk [(total_vf > 0.0 ) & (total_ff > 0.0 )] = 1
102
+
103
+ if isdefined (self .inputs .in_mask ):
104
+ msk = nb .load (self .inputs .in_mask ).get_data ()
105
+ msk [msk > 0.0 ] = 1.0
106
+ msk [msk < 1.0 ] = 0.0
107
+
108
+ mhdr = hdr .copy ()
109
+ mhdr .set_data_dtype (np .uint8 )
110
+ mhdr .set_xyzt_units ('mm' , 'sec' )
111
+ nb .Nifti1Image (msk , aff , mhdr ).to_filename (
112
+ op .abspath (self .inputs .out_mask ))
113
+
114
+ for f in self .inputs .in_dirs :
115
+ fd = nb .load (f ).get_data ()
116
+ x = fd [msk > 0 ][..., 0 ]
117
+ y = fd [msk > 0 ][..., 1 ]
118
+ z = fd [msk > 0 ][..., 2 ]
119
+ th = np .arccos (z / np .sqrt (x ** 2 + y ** 2 + z ** 2 ))
120
+ ph = np .arctan2 (y , x )
121
+ thetas .append (th )
122
+ phis .append (ph )
79
123
80
124
# Load the gradient strengths and directions
81
- bvals = np .loadtxt (self .inputs .bvals )
82
- gradients = np .loadtxt (self .inputs .bvecs ).T
125
+ bvals = np .loadtxt (self .inputs .bval )
126
+ gradients = np .loadtxt (self .inputs .bvec ).T
83
127
84
128
# Place in Dipy's preferred format
85
129
gtab = GradientTable (gradients )
86
130
gtab .bvals = bvals
131
+
132
+ return runtime
133
+
134
+ def _list_outputs (self ):
135
+ outputs = self ._outputs ().get ()
136
+ outputs ['out_file' ] = op .abspath (self .inputs .out_file )
137
+ outputs ['out_mask' ] = op .abspath (self .inputs .out_mask )
138
+ return outputs
139
+
140
+
141
+ def _compute_voxel (vfs , ffs , ths , phs , S0 , gtab , snr = None ,
142
+ csf_evals = [0.0015 , 0.0015 , 0.0015 ],
143
+ gm_evals = [0.0007 , 0.0007 , 0.0007 ],
144
+ wm_evals = [0.0015 , 0.0003 , 0.0003 ]):
145
+
146
+ nf = len (ffs )
147
+ total_ff = np .sum (ffs )
148
+
149
+ gm_vf = vfs [1 ] * (1 - total_ff ) / (vfs [0 ] + vfs [1 ])
150
+ ffs .insert (0 , gm_vf )
151
+ csf_vf = vfs [0 ] * (1 - total_ff ) / (vfs [0 ] + vfs [1 ])
152
+ ffs .insert (0 , csf_vf )
153
+ angles = [(0 , 0 ), (0 , 0 )] # angles of gm and csf
154
+ angles += [(th , ph ) for ph , th in zip (ths , phs )]
155
+
156
+ mevals = np .array ([csf_evals , gm_evals ] + [wm_evals ] * nf )
157
+ ffs = np .array (ffs ) * 100
158
+ signal , sticks = multi_tensor (gtab , mevals , S0 = S0 , angles = angles ,
159
+ fractions = ffs , snr = snr )
160
+ return signal , sticks
0 commit comments