Skip to content

Commit 161c941

Browse files
committed
Merge pull request #64 from matthew-brett/mat-rw-fixes
BF+TST - SPM analyze had 111 voxel offset in mats
2 parents 4e289b1 + 7a39f7c commit 161c941

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

nibabel/spm99analyze.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,6 @@ def from_file_map(klass, file_map):
261261
'using first')
262262
mat = mat[:, :, 0]
263263
ret._affine = mat
264-
return ret
265264
elif 'M' in mats: # the 'M' matrix does not include flips
266265
hdr = ret._header
267266
if hdr.default_x_flip:
@@ -270,6 +269,10 @@ def from_file_map(klass, file_map):
270269
ret._affine = mats['M']
271270
else:
272271
raise ValueError('mat file found but no "mat" or "M" in it')
272+
# Adjust for matlab 1,1,1 voxel origin
273+
to_111 = np.eye(4)
274+
to_111[:3,3] = 1
275+
ret._affine = np.dot(ret._affine, to_111)
273276
return ret
274277

275278
def to_file_map(self, file_map=None):
@@ -295,6 +298,11 @@ def to_file_map(self, file_map=None):
295298
M = np.dot(np.diag([-1, 1, 1, 1]), mat)
296299
else:
297300
M = mat
301+
# Adjust for matlab 1,1,1 voxel origin
302+
from_111 = np.eye(4)
303+
from_111[:3,3] = -1
304+
M = np.dot(M, from_111)
305+
mat = np.dot(mat, from_111)
298306
# use matlab 4 format to allow gzipped write without error
299307
mfobj = file_map['mat'].get_prepare_fileobj(mode='wb')
300308
sio.savemat(mfobj, {'M': M, 'mat': mat}, format='4')

nibabel/tests/test_spm99analyze.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,59 @@ class TestSpm99AnalyzeImage(test_analyze.TestAnalyzeImage):
105105
test_analyze.TestAnalyzeImage.test_data_hdr_cache
106106
))
107107

108+
@scipy_skip
109+
def test_mat_read(self):
110+
# Test mat file reading and writing for the SPM analyze types
111+
img_klass = self.image_class
112+
arr = np.arange(24).reshape((2,3,4))
113+
aff = np.diag([2,3,4,1]) # no LR flip in affine
114+
img = img_klass(arr, aff)
115+
fm = img.file_map
116+
for key, value in fm.items():
117+
value.fileobj = BytesIO()
118+
# Test round trip
119+
img.to_file_map()
120+
r_img = img_klass.from_file_map(fm)
121+
assert_array_equal(r_img.get_data(), arr)
122+
assert_array_equal(r_img.get_affine(), aff)
123+
# mat files are for matlab and have 111 voxel origins. We need to
124+
# adjust for that, when loading and saving. Check for signs of that in
125+
# the saved mat file
126+
mat_fileobj = img.file_map['mat'].fileobj
127+
from scipy.io import loadmat, savemat
128+
mat_fileobj.seek(0)
129+
mats = loadmat(mat_fileobj)
130+
assert_true('M' in mats and 'mat' in mats)
131+
from_111 = np.eye(4)
132+
from_111[:3,3] = -1
133+
to_111 = np.eye(4)
134+
to_111[:3,3] = 1
135+
assert_array_equal(mats['mat'], np.dot(aff, from_111))
136+
# The M matrix does not include flips, so if we only
137+
# have the M matrix in the mat file, and we have default flipping, the
138+
# mat resulting should have a flip. The 'mat' matrix does include flips
139+
# and so should be unaffected by the flipping. If both are present we
140+
# prefer the the 'mat' matrix.
141+
assert_true(img.get_header().default_x_flip) # check the default
142+
flipper = np.diag([-1,1,1,1])
143+
assert_array_equal(mats['M'], np.dot(aff, np.dot(flipper, from_111)))
144+
mat_fileobj.seek(0)
145+
savemat(mat_fileobj, dict(M=np.diag([3,4,5,1]), mat=np.diag([6,7,8,1])))
146+
# Check we are preferring the 'mat' matrix
147+
r_img = img_klass.from_file_map(fm)
148+
assert_array_equal(r_img.get_data(), arr)
149+
assert_array_equal(r_img.get_affine(),
150+
np.dot(np.diag([6,7,8,1]), to_111))
151+
# But will use M if present
152+
mat_fileobj.seek(0)
153+
mat_fileobj.truncate(0)
154+
savemat(mat_fileobj, dict(M=np.diag([3,4,5,1])))
155+
r_img = img_klass.from_file_map(fm)
156+
assert_array_equal(r_img.get_data(), arr)
157+
assert_array_equal(r_img.get_affine(),
158+
np.dot(np.diag([3,4,5,1]), np.dot(flipper, to_111)))
159+
160+
108161

109162
def test_origin_affine():
110163
hdr = Spm99AnalyzeHeader()

0 commit comments

Comments
 (0)