16
16
17
17
from ..tmpdirs import InTemporaryDirectory
18
18
from ..loadsave import load
19
+ from ..orientations import flip_axis , aff2axcodes , inv_ornt_aff
19
20
20
21
from nose .tools import (assert_true , assert_false , assert_not_equal ,
21
22
assert_equal )
22
23
23
- from numpy .testing import assert_almost_equal
24
+ from numpy .testing import assert_almost_equal , assert_array_equal
24
25
25
26
from .scriptrunner import ScriptRunner
26
27
from .nibabel_data import needs_nibabel_data
27
- from .test_parrec import DTI_PAR_BVECS , DTI_PAR_BVALS
28
+ from ..testing import assert_dt_equal
29
+ from .test_parrec import (DTI_PAR_BVECS , DTI_PAR_BVALS ,
30
+ EXAMPLE_IMAGES as PARREC_EXAMPLES )
28
31
from .test_parrec_data import BALLS , AFF_OFF
32
+ from .test_helpers import assert_data_similar
29
33
30
34
31
35
def _proc_stdout (stdout ):
@@ -83,31 +87,88 @@ def vox_size(affine):
83
87
return np .sqrt (np .sum (affine [:3 ,:3 ] ** 2 , axis = 0 ))
84
88
85
89
90
+ def check_conversion (cmd , pr_data , out_fname ):
91
+ run_command (cmd )
92
+ img = load (out_fname )
93
+ # Check orientations always LAS
94
+ assert_equal (aff2axcodes (img .affine ), tuple ('LAS' ))
95
+ data = img .get_data ()
96
+ assert_true (np .allclose (data , pr_data ))
97
+ assert_true (np .allclose (img .header ['cal_min' ], data .min ()))
98
+ assert_true (np .allclose (img .header ['cal_max' ], data .max ()))
99
+ # Check minmax options
100
+ run_command (cmd + ['--minmax' , '1' , '2' ])
101
+ img = load (out_fname )
102
+ assert_true (np .allclose (data , pr_data ))
103
+ assert_true (np .allclose (img .header ['cal_min' ], 1 ))
104
+ assert_true (np .allclose (img .header ['cal_max' ], 2 ))
105
+ run_command (cmd + ['--minmax' , 'parse' , '2' ])
106
+ img = load (out_fname )
107
+ assert_true (np .allclose (data , pr_data ))
108
+ assert_true (np .allclose (img .header ['cal_min' ], data .min ()))
109
+ assert_true (np .allclose (img .header ['cal_max' ], 2 ))
110
+ run_command (cmd + ['--minmax' , '1' , 'parse' ])
111
+ img = load (out_fname )
112
+ assert_true (np .allclose (data , pr_data ))
113
+ assert_true (np .allclose (img .header ['cal_min' ], 1 ))
114
+ assert_true (np .allclose (img .header ['cal_max' ], data .max ()))
115
+
116
+
86
117
@script_test
87
118
def test_parrec2nii ():
88
119
# Test parrec2nii script
89
120
cmd = ['parrec2nii' , '--help' ]
90
121
code , stdout , stderr = run_command (cmd )
91
122
assert_true (stdout .startswith ('Usage' ))
92
- in_fname = pjoin (DATA_PATH , 'phantom_EPI_asc_CLEAR_2_1.PAR' )
93
- out_froot = 'phantom_EPI_asc_CLEAR_2_1.nii'
94
123
with InTemporaryDirectory ():
95
- run_command (['parrec2nii' , in_fname ])
96
- img = load (out_froot )
97
- assert_equal (img .shape , (64 , 64 , 9 , 3 ))
98
- assert_equal (img .get_data_dtype (), np .dtype (np .uint16 ))
99
- # Check against values from Philips converted nifti image
100
- data = img .get_data ()
101
- assert_true (np .allclose (
102
- (data .min (), data .max (), data .mean ()),
103
- (0.0 , 2299.4110643863678 , 194.95876256117265 )))
104
- assert_almost_equal (vox_size (img .get_affine ()), (3.75 , 3.75 , 8 ))
124
+ for eg_dict in PARREC_EXAMPLES :
125
+ fname = eg_dict ['fname' ]
126
+ run_command (['parrec2nii' , fname ])
127
+ out_froot = splitext (basename (fname ))[0 ] + '.nii'
128
+ img = load (out_froot )
129
+ assert_equal (img .shape , eg_dict ['shape' ])
130
+ assert_dt_equal (img .get_data_dtype (), eg_dict ['dtype' ])
131
+ # Check against values from Philips converted nifti image
132
+ data = img .get_data ()
133
+ assert_data_similar (data , eg_dict )
134
+ assert_almost_equal (img .header .get_zooms (), eg_dict ['zooms' ])
135
+ # Standard save does not save extensions
136
+ assert_equal (len (img .header .extensions ), 0 )
137
+ # Does not overwrite unless option given
138
+ code , stdout , stderr = run_command (
139
+ ['parrec2nii' , fname ], check_code = False )
140
+ assert_equal (code , 1 )
141
+ # Default scaling is dv
142
+ pr_img = load (fname )
143
+ flipped_data = flip_axis (pr_img .get_data (), 1 )
144
+ base_cmd = ['parrec2nii' , '--overwrite' , fname ]
145
+ check_conversion (base_cmd , flipped_data , out_froot )
146
+ check_conversion (base_cmd + ['--scaling=dv' ],
147
+ flipped_data ,
148
+ out_froot )
149
+ # fp
150
+ pr_img = load (fname , scaling = 'fp' )
151
+ flipped_data = flip_axis (pr_img .get_data (), 1 )
152
+ check_conversion (base_cmd + ['--scaling=fp' ],
153
+ flipped_data ,
154
+ out_froot )
155
+ # no scaling
156
+ unscaled_flipped = flip_axis (pr_img .dataobj .get_unscaled (), 1 )
157
+ check_conversion (base_cmd + ['--scaling=off' ],
158
+ unscaled_flipped ,
159
+ out_froot )
160
+ # Save extensions
161
+ run_command (base_cmd + ['--store-header' ])
162
+ img = load (out_froot )
163
+ assert_equal (len (img .header .extensions ), 1 )
105
164
106
165
107
166
@script_test
108
167
@needs_nibabel_data ('nitest-balls1' )
109
168
def test_parrec2nii_with_data ():
110
169
# Use nibabel-data to test conversion
170
+ # Premultiplier to relate our affines to Philips conversion
171
+ LAS2LPS = inv_ornt_aff ([[0 , 1 ], [1 , - 1 ], [2 , 1 ]], (80 , 80 , 10 ))
111
172
with InTemporaryDirectory ():
112
173
for par in glob (pjoin (BALLS , 'PARREC' , '*.PAR' )):
113
174
par_root , ext = splitext (basename (par ))
@@ -118,23 +179,31 @@ def test_parrec2nii_with_data():
118
179
# Do conversion
119
180
run_command (['parrec2nii' , par ])
120
181
conved_img = load (par_root + '.nii' )
182
+ # Confirm parrec2nii conversions are LAS
183
+ assert_equal (aff2axcodes (conved_img .affine ), tuple ('LAS' ))
184
+ # Shape same whether LPS or LAS
121
185
assert_equal (conved_img .shape [:3 ], (80 , 80 , 10 ))
122
- # Test against converted NIfTI
186
+ # Test against original converted NIfTI
123
187
nifti_fname = pjoin (BALLS , 'NIFTI' , par_root + '.nii.gz' )
124
188
if exists (nifti_fname ):
125
- nimg = load (nifti_fname )
126
- assert_almost_equal (nimg .affine [:3 , :3 ],
127
- conved_img .affine [:3 , :3 ], 3 )
189
+ philips_img = load (nifti_fname )
190
+ # Confirm Philips converted image always LPS
191
+ assert_equal (aff2axcodes (philips_img .affine ), tuple ('LPS' ))
192
+ # Equivalent to Philips LPS affine
193
+ equiv_affine = conved_img .affine .dot (LAS2LPS )
194
+ assert_almost_equal (philips_img .affine [:3 , :3 ],
195
+ equiv_affine [:3 , :3 ], 3 )
128
196
# The translation part is always off by the same ammout
129
- aff_off = conved_img . affine [:3 , 3 ] - nimg .affine [:3 , 3 ]
130
- assert_almost_equal (aff_off , AFF_OFF , 4 )
197
+ aff_off = equiv_affine [:3 , 3 ] - philips_img .affine [:3 , 3 ]
198
+ assert_almost_equal (aff_off , AFF_OFF , 3 )
131
199
# The difference is max in the order of 0.5 voxel
132
- vox_sizes = np . sqrt (( nimg .affine [: 3 , : 3 ] ** 2 ). sum ( axis = 0 ) )
200
+ vox_sizes = vox_size ( philips_img .affine )
133
201
assert_true (np .all (np .abs (aff_off / vox_sizes ) <= 0.5 ))
134
202
# The data is very close, unless it's the fieldmap
135
203
if par_root != 'fieldmap' :
136
- assert_true (np .allclose (conved_img .dataobj ,
137
- nimg .dataobj ))
204
+ conved_data_lps = flip_axis (conved_img .dataobj , 1 )
205
+ assert_true (np .allclose (conved_data_lps ,
206
+ philips_img .dataobj ))
138
207
with InTemporaryDirectory ():
139
208
# Test some options
140
209
dti_par = pjoin (BALLS , 'PARREC' , 'DTI.PAR' )
@@ -149,8 +218,12 @@ def test_parrec2nii_with_data():
149
218
# Writes bvals, bvecs files if asked
150
219
run_command (['parrec2nii' , '--overwrite' , '--bvs' , dti_par ])
151
220
assert_almost_equal (np .loadtxt ('DTI.bvals' ), DTI_PAR_BVALS )
152
- assert_almost_equal (np .loadtxt ('DTI.bvecs' ),
153
- DTI_PAR_BVECS [:, [2 , 0 , 1 ]].T )
221
+ # Bvecs in header, transposed from PSL to LPS
222
+ bvecs_LPS = DTI_PAR_BVECS [:, [2 , 0 , 1 ]]
223
+ # Adjust for output flip of Y axis in data and bvecs
224
+ bvecs_LAS = bvecs_LPS * [1 , - 1 , 1 ]
225
+ assert_almost_equal (np .loadtxt ('DTI.bvecs' ), bvecs_LAS .T )
226
+ # Dwell time
154
227
assert_false (exists ('DTI.dwell_time' ))
155
228
# Need field strength if requesting dwell time
156
229
code , _ , _ , = run_command (
0 commit comments