1616
1717from ..tmpdirs import InTemporaryDirectory
1818from ..loadsave import load
19+ from ..orientations import flip_axis , aff2axcodes , inv_ornt_aff
1920
2021from nose .tools import (assert_true , assert_false , assert_not_equal ,
2122 assert_equal )
2223
23- from numpy .testing import assert_almost_equal
24+ from numpy .testing import assert_almost_equal , assert_array_equal
2425
2526from .scriptrunner import ScriptRunner
2627from .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 )
2831from .test_parrec_data import BALLS , AFF_OFF
32+ from .test_helpers import assert_data_similar
2933
3034
3135def _proc_stdout (stdout ):
@@ -83,31 +87,88 @@ def vox_size(affine):
8387 return np .sqrt (np .sum (affine [:3 ,:3 ] ** 2 , axis = 0 ))
8488
8589
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+
86117@script_test
87118def test_parrec2nii ():
88119 # Test parrec2nii script
89120 cmd = ['parrec2nii' , '--help' ]
90121 code , stdout , stderr = run_command (cmd )
91122 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'
94123 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 )
105164
106165
107166@script_test
108167@needs_nibabel_data ('nitest-balls1' )
109168def test_parrec2nii_with_data ():
110169 # 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 ))
111172 with InTemporaryDirectory ():
112173 for par in glob (pjoin (BALLS , 'PARREC' , '*.PAR' )):
113174 par_root , ext = splitext (basename (par ))
@@ -118,23 +179,31 @@ def test_parrec2nii_with_data():
118179 # Do conversion
119180 run_command (['parrec2nii' , par ])
120181 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
121185 assert_equal (conved_img .shape [:3 ], (80 , 80 , 10 ))
122- # Test against converted NIfTI
186+ # Test against original converted NIfTI
123187 nifti_fname = pjoin (BALLS , 'NIFTI' , par_root + '.nii.gz' )
124188 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 )
128196 # 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 )
131199 # 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 )
133201 assert_true (np .all (np .abs (aff_off / vox_sizes ) <= 0.5 ))
134202 # The data is very close, unless it's the fieldmap
135203 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 ))
138207 with InTemporaryDirectory ():
139208 # Test some options
140209 dti_par = pjoin (BALLS , 'PARREC' , 'DTI.PAR' )
@@ -149,8 +218,12 @@ def test_parrec2nii_with_data():
149218 # Writes bvals, bvecs files if asked
150219 run_command (['parrec2nii' , '--overwrite' , '--bvs' , dti_par ])
151220 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
154227 assert_false (exists ('DTI.dwell_time' ))
155228 # Need field strength if requesting dwell time
156229 code , _ , _ , = run_command (
0 commit comments