# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the NiBabel package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## import numpy as np from ..py3k import BytesIO from numpy.testing import assert_array_equal, assert_array_almost_equal, dec # Decorator to skip tests requiring save / load if scipy not available for mat # files try: import scipy except ImportError: have_scipy = False else: have_scipy = True scipy_skip = dec.skipif(not have_scipy, 'scipy not available') from ..spm99analyze import (Spm99AnalyzeHeader, Spm99AnalyzeImage, HeaderTypeError) from ..casting import type_info from ..testing import (assert_equal, assert_true, assert_false, assert_raises) from . import test_analyze class TestSpm99AnalyzeHeader(test_analyze.TestAnalyzeHeader): header_class = Spm99AnalyzeHeader def test_empty(self): super(TestSpm99AnalyzeHeader, self).test_empty() hdr = self.header_class() assert_equal(hdr['scl_slope'], 1) def test_scaling(self): hdr = self.header_class() hdr.set_data_shape((1,2,3)) hdr.set_data_dtype(np.int16) S3 = BytesIO() data = np.arange(6, dtype=np.float64).reshape((1,2,3)) # This uses scaling hdr.data_to_fileobj(data, S3) data_back = hdr.data_from_fileobj(S3) assert_array_almost_equal(data, data_back, 4) # This is exactly the same call, just testing it works twice data_back2 = hdr.data_from_fileobj(S3) assert_array_equal(data_back, data_back2, 4) def test_big_scaling(self): # Test that upcasting works for huge scalefactors # See tests for apply_read_scaling in test_utils hdr = self.header_class() hdr.set_data_shape((1,1,1)) hdr.set_data_dtype(np.int16) sio = BytesIO() dtt = np.float32 # This will generate a huge scalefactor data = np.array([type_info(dtt)['max']], dtype=dtt)[:,None, None] hdr.data_to_fileobj(data, sio) data_back = hdr.data_from_fileobj(sio) assert_true(np.allclose(data, data_back)) def test_origin_checks(self): HC = self.header_class # origin hdr = HC() hdr.data_shape = [1,1,1] hdr['origin'][0] = 101 # severity 20 fhdr, message, raiser = self.log_chk(hdr, 20) assert_equal(fhdr, hdr) assert_equal(message, 'very large origin values ' 'relative to dims; leaving as set, ' 'ignoring for affine') assert_raises(*raiser) # diagnose binary block dxer = self.header_class.diagnose_binaryblock assert_equal(dxer(hdr.binaryblock), 'very large origin values ' 'relative to dims') def test_spm_scale_checks(self): # checks for scale hdr = self.header_class() hdr['scl_slope'] = np.nan # NaN and Inf string representation can be odd on windows, so we # check against the representation on this system fhdr, message, raiser = self.log_chk(hdr, 30) assert_equal(fhdr['scl_slope'], 1) assert_equal(message, 'scale slope is %s; ' 'should be finite; ' 'setting scalefactor "scl_slope" to 1' % np.nan) assert_raises(*raiser) dxer = self.header_class.diagnose_binaryblock assert_equal(dxer(hdr.binaryblock), 'scale slope is %s; ' 'should be finite' % np.nan) hdr['scl_slope'] = np.inf # Inf string representation can be odd on windows assert_equal(dxer(hdr.binaryblock), 'scale slope is %s; ' 'should be finite' % np.inf) class TestSpm99AnalyzeImage(test_analyze.TestAnalyzeImage): # class for testing images image_class = Spm99AnalyzeImage # Decorating the old way, before the team invented @ test_data_hdr_cache = (scipy_skip( test_analyze.TestAnalyzeImage.test_data_hdr_cache )) test_header_updating = (scipy_skip( test_analyze.TestAnalyzeImage.test_header_updating )) @scipy_skip def test_mat_read(self): # Test mat file reading and writing for the SPM analyze types img_klass = self.image_class arr = np.arange(24, dtype=np.int32).reshape((2,3,4)) aff = np.diag([2,3,4,1]) # no LR flip in affine img = img_klass(arr, aff) fm = img.file_map for key, value in fm.items(): value.fileobj = BytesIO() # Test round trip img.to_file_map() r_img = img_klass.from_file_map(fm) assert_array_equal(r_img.get_data(), arr) assert_array_equal(r_img.get_affine(), aff) # mat files are for matlab and have 111 voxel origins. We need to # adjust for that, when loading and saving. Check for signs of that in # the saved mat file mat_fileobj = img.file_map['mat'].fileobj from scipy.io import loadmat, savemat mat_fileobj.seek(0) mats = loadmat(mat_fileobj) assert_true('M' in mats and 'mat' in mats) from_111 = np.eye(4) from_111[:3,3] = -1 to_111 = np.eye(4) to_111[:3,3] = 1 assert_array_equal(mats['mat'], np.dot(aff, from_111)) # The M matrix does not include flips, so if we only # have the M matrix in the mat file, and we have default flipping, the # mat resulting should have a flip. The 'mat' matrix does include flips # and so should be unaffected by the flipping. If both are present we # prefer the the 'mat' matrix. assert_true(img.get_header().default_x_flip) # check the default flipper = np.diag([-1,1,1,1]) assert_array_equal(mats['M'], np.dot(aff, np.dot(flipper, from_111))) mat_fileobj.seek(0) savemat(mat_fileobj, dict(M=np.diag([3,4,5,1]), mat=np.diag([6,7,8,1]))) # Check we are preferring the 'mat' matrix r_img = img_klass.from_file_map(fm) assert_array_equal(r_img.get_data(), arr) assert_array_equal(r_img.get_affine(), np.dot(np.diag([6,7,8,1]), to_111)) # But will use M if present mat_fileobj.seek(0) mat_fileobj.truncate(0) savemat(mat_fileobj, dict(M=np.diag([3,4,5,1]))) r_img = img_klass.from_file_map(fm) assert_array_equal(r_img.get_data(), arr) assert_array_equal(r_img.get_affine(), np.dot(np.diag([3,4,5,1]), np.dot(flipper, to_111))) def test_none_affine(self): # Allow for possibility of no affine resulting in nothing written into # mat file. If the mat file is a filename, we just get no file, but if # it's a fileobj, we get an empty fileobj img_klass = self.image_class # With a None affine - no matfile written img = img_klass(np.zeros((2,3,4)), None) aff = img.get_header().get_best_affine() # Save / reload using bytes IO objects for key, value in img.file_map.items(): value.fileobj = BytesIO() img.to_file_map() img_back = img.from_file_map(img.file_map) assert_array_equal(img_back.get_affine(), aff) def test_origin_affine(): hdr = Spm99AnalyzeHeader() aff = hdr.get_origin_affine() assert_array_equal(aff, hdr.get_base_affine()) hdr.set_data_shape((3, 5, 7)) hdr.set_zooms((3, 2, 1)) assert_true(hdr.default_x_flip) assert_array_almost_equal( hdr.get_origin_affine(), # from center of image [[-3., 0., 0., 3.], [ 0., 2., 0., -4.], [ 0., 0., 1., -3.], [ 0., 0., 0., 1.]]) hdr['origin'][:3] = [3,4,5] assert_array_almost_equal( hdr.get_origin_affine(), # using origin [[-3., 0., 0., 6.], [ 0., 2., 0., -6.], [ 0., 0., 1., -4.], [ 0., 0., 0., 1.]]) hdr['origin'] = 0 # unset origin hdr.set_data_shape((3, 5)) assert_array_almost_equal( hdr.get_origin_affine(), [[-3., 0., 0., 3.], [ 0., 2., 0., -4.], [ 0., 0., 1., -0.], [ 0., 0., 0., 1.]]) hdr.set_data_shape((3, 5, 7)) assert_array_almost_equal( hdr.get_origin_affine(), # from center of image [[-3., 0., 0., 3.], [ 0., 2., 0., -4.], [ 0., 0., 1., -3.], [ 0., 0., 0., 1.]]) def test_slope_inter(): hdr = Spm99AnalyzeHeader() assert_equal(hdr.get_slope_inter(), (1.0, None)) for intup, outup in (((2.0,), (2.0, None)), ((None,), (None, None)), ((1.0, None), (1.0, None)), ((0.0, None), (None, None)), ((None, 0.0), (None, None))): hdr.set_slope_inter(*intup) assert_equal(hdr.get_slope_inter(), outup) # Check set survives through checking hdr = Spm99AnalyzeHeader.from_header(hdr, check=True) assert_equal(hdr.get_slope_inter(), outup) # Setting not-zero to offset raises error assert_raises(HeaderTypeError, hdr.set_slope_inter, None, 1.1) assert_raises(HeaderTypeError, hdr.set_slope_inter, 2.0, 1.1)