Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 79a5876

Browse files
committedNov 23, 2017
REVERT renamed/reshaped header fields
1 parent 332aed7 commit 79a5876

File tree

2 files changed

+48
-80
lines changed

2 files changed

+48
-80
lines changed
 

‎nibabel/freesurfer/mghformat.py

+32-54
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,10 @@
3232
('dims', '>i4', (4,)), # 4; width, height, depth, nframes
3333
('type', '>i4'), # 20; data type
3434
('dof', '>i4'), # 24; degrees of freedom
35-
('ras_good', '>i2'), # 28; *_ras fields valid
36-
('voxelsize', '>f4', (3,)), # 30; zooms (X, Y, Z)
37-
('x_ras', '>f4', (3, 1)), # 42; X direction cosine column
38-
('y_ras', '>f4', (3, 1)), # 54; Y direction cosine column
39-
('z_ras', '>f4', (3, 1)), # 66; Z direction cosine column
40-
('c_ras', '>f4', (3, 1)), # 78; mm from (0, 0, 0) RAS to vol center
35+
('goodRASFlag', '>i2'), # 28; Mdc, Pxyz_c fields valid
36+
('delta', '>f4', (3,)), # 30; zooms (X, Y, Z)
37+
('Mdc', '>f4', (3, 3)), # 42; TRANSPOSE of direction cosine matrix
38+
('Pxyz_c', '>f4', (3,)), # 78; mm from (0, 0, 0) RAS to vol center
4139
]
4240
# Optional footer. Also has more stuff after this, optionally
4341
footer_dtd = [
@@ -120,7 +118,7 @@ def __init__(self,
120118
super(MGHHeader, self).__init__(binaryblock=binaryblock,
121119
endianness=endianness,
122120
check=False)
123-
if not self._structarr['ras_good']:
121+
if not self._structarr['goodRASFlag']:
124122
self._set_affine_default()
125123
if check:
126124
self.check_fix()
@@ -165,13 +163,12 @@ def get_affine(self):
165163
166164
MGH format doesn't store the transform directly. Instead it's gleaned
167165
from the zooms ( delta ), direction cosines ( Mdc ), RAS centers (
168-
c_ras ) and the dimensions.
166+
Pxyz_c ) and the dimensions.
169167
'''
170-
affine = np.eye(4)
171168
hdr = self._structarr
172-
MdcD = np.hstack((hdr['x_ras'], hdr['y_ras'], hdr['z_ras'])) * hdr['voxelsize']
169+
MdcD = hdr['Mdc'].T * hdr['delta']
173170
vol_center = MdcD.dot(hdr['dims'][:3]) / 2
174-
return from_matvec(MdcD, hdr['c_ras'].T - vol_center)
171+
return from_matvec(MdcD, hdr['Pxyz_c'] - vol_center)
175172

176173
# For compatibility with nifti (multiple affines)
177174
get_best_affine = get_affine
@@ -185,7 +182,7 @@ def get_vox2ras_tkr(self):
185182
''' Get the vox2ras-tkr transform. See "Torig" here:
186183
https://surfer.nmr.mgh.harvard.edu/fswiki/CoordinateSystems
187184
'''
188-
ds = self._structarr['voxelsize']
185+
ds = self._structarr['delta']
189186
ns = self._structarr['dims'][:3] * ds / 2.0
190187
v2rtkr = np.array([[-ds[0], 0, 0, ns[0]],
191188
[0, 0, ds[2], -ns[2]],
@@ -235,7 +232,7 @@ def get_zooms(self):
235232
For four-dimensional files, a fourth zoom is included, equal to the
236233
repetition time (TR) in ms.
237234
238-
To access only the spatial zooms, use `hdr['voxelsize']`.
235+
To access only the spatial zooms, use `hdr['delta']`.
239236
240237
Returns
241238
-------
@@ -244,7 +241,7 @@ def get_zooms(self):
244241
'''
245242
# Do not return time zoom (TR) if 3D image
246243
tzoom = (self['tr'],)[:self._ndims() > 3]
247-
return tuple(self._structarr['voxelsize']) + tzoom
244+
return tuple(self._structarr['delta']) + tzoom
248245

249246
def set_zooms(self, zooms):
250247
''' Set zooms into header fields
@@ -266,7 +263,7 @@ def set_zooms(self, zooms):
266263
raise HeaderDataError('Expecting %d zoom values' % ndims)
267264
if np.any(zooms <= 0):
268265
raise HeaderDataError('zooms must be positive')
269-
hdr['voxelsize'] = zooms[:3]
266+
hdr['delta'] = zooms[:3]
270267
if len(zooms) == 4:
271268
hdr['tr'] = zooms[3]
272269

@@ -292,7 +289,7 @@ def set_data_shape(self, shape):
292289
if len(shape) > 4:
293290
raise ValueError("Shape may be at most 4 dimensional")
294291
self._structarr['dims'] = shape + (1,) * (4 - len(shape))
295-
self._structarr['voxelsize'] = 1
292+
self._structarr['delta'] = 1
296293

297294
def get_data_bytespervox(self):
298295
''' Get the number of bytes per voxel of the data
@@ -357,22 +354,18 @@ def default_structarr(klass, endianness=None):
357354
structarr['version'] = 1
358355
structarr['dims'] = 1
359356
structarr['type'] = 3
360-
structarr['ras_good'] = 1
361-
structarr['voxelsize'] = 1
362-
structarr['x_ras'][0] = -1
363-
structarr['y_ras'][2] = 1
364-
structarr['z_ras'][1] = -1
357+
structarr['goodRASFlag'] = 1
358+
structarr['delta'] = 1
359+
structarr['Mdc'] = [[-1, 0, 0], [0, 0, 1], [0, -1, 0]]
365360
return structarr
366361

367362
def _set_affine_default(self):
368-
''' If ras_good flag is 0, set the default affine
363+
''' If goodRASFlag is 0, set the default affine
369364
'''
370-
self._structarr['ras_good'] = 1
371-
self._structarr['voxelsize'] = 1
372-
self._structarr['x_ras'] = [[-1], [0], [0]]
373-
self._structarr['y_ras'] = [[0], [0], [1]]
374-
self._structarr['z_ras'] = [[0], [-1], [0]]
375-
self._structarr['c_ras'] = 0
365+
self._structarr['goodRASFlag'] = 1
366+
self._structarr['delta'] = 1
367+
self._structarr['Mdc'] = [[-1, 0, 0], [0, 0, 1], [0, -1, 0]]
368+
self._structarr['Pxyz_c'] = 0
376369

377370
def writehdr_to(self, fileobj):
378371
''' Write header to fileobj
@@ -416,35 +409,20 @@ def writeftr_to(self, fileobj):
416409

417410
class _HeaderData:
418411
""" Provide interface to deprecated MGHHeader fields"""
419-
renamed = {'goodRASFlag': 'ras_good',
420-
'delta': 'voxelsize'}
421412
def __init__(self, structarr):
422413
self._structarr = structarr
423414

424415
def __getitem__(self, item):
425416
sa = self._structarr
426-
if item == 'Mdc':
427-
return np.hstack((sa['x_ras'], sa['y_ras'], sa['z_ras'])).T
428-
elif item == 'Pxyz_c':
429-
return sa['c_ras'][:, 0]
430-
elif item == 'mrparams':
417+
if item == 'mrparams':
431418
return np.hstack((sa['tr'], sa['flip_angle'], sa['te'], sa['ti']))
432-
elif item in self.renamed:
433-
item = self.renamed[item]
434419
return sa[item]
435420

436421
def __setitem__(self, item, val):
437422
sa = self._structarr
438-
if item == 'Mdc':
439-
sa['x_ras'][:, 0], sa['y_ras'][:, 0], sa['z_ras'][:, 0] = val
440-
elif item == 'Pxyz_c':
441-
sa['c_ras'][:, 0] = val
442-
elif item == 'mrparams':
443-
return sa['tr'], sa['flip_angle'], sa['te'], sa['ti'] = val
444-
else:
445-
if item in self.renamed.values():
446-
item = {v: k for k, v in self.renamed.items()}[item]
447-
sa[item] = val
423+
if item == 'mrparams':
424+
sa['tr'], sa['flip_angle'], sa['te'], sa['ti'] = val
425+
sa[item] = val
448426

449427
@property
450428
@deprecate_with_version('_header_data is deprecated.\n'
@@ -457,12 +435,12 @@ def _header_data(self):
457435
return self._HeaderData(self._structarr)
458436

459437
def __getitem__(self, item):
460-
if item in ('goodRASFlag', 'delta', 'Mdc', 'Pxyz_c', 'mrparams'):
438+
if item == 'mrparams':
461439
return self._header_data[item]
462440
return super(MGHHeader, self).__getitem__(item)
463441

464442
def __setitem__(self, item, value):
465-
if item in ('goodRASFlag', 'delta', 'Mdc', 'Pxyz_c', 'mrparams'):
443+
if item == 'mrparams':
466444
self._header_data[item] = value
467445
super(MGHHeader, self).__setitem__(item, value)
468446

@@ -627,17 +605,17 @@ def _write_data(self, mghfile, data, header):
627605
def _affine2header(self):
628606
""" Unconditionally set affine into the header """
629607
hdr = self._header
630-
shape = np.array(self._dataobj.shape[:3]).reshape(-1, 1)
608+
shape = np.array(self._dataobj.shape[:3])
631609

632610
# for more information, go through save_mgh.m in FreeSurfer dist
633611
voxelsize = voxel_sizes(self._affine)
634612
Mdc = self._affine[:3, :3] / voxelsize
635-
c_ras = self._affine.dot(np.vstack((shape / 2.0, [1])))[:3]
613+
c_ras = self._affine.dot(np.hstack((shape / 2.0, [1])))[:3]
636614

637615
# Assign after we've had a chance to raise exceptions
638-
hdr['voxelsize'] = voxelsize
639-
hdr['x_ras'][:, 0], hdr['y_ras'][:, 0], hdr['z_ras'][:, 0] = Mdc.T
640-
hdr['c_ras'] = c_ras
616+
hdr['delta'] = voxelsize
617+
hdr['Mdc'] = Mdc.T
618+
hdr['Pxyz_c'] = c_ras
641619

642620

643621
load = MGHImage.load

‎nibabel/freesurfer/tests/test_mghformat.py

+16-26
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_read_mgh():
5353
assert_equal(h['version'], 1)
5454
assert_equal(h['type'], 3)
5555
assert_equal(h['dof'], 0)
56-
assert_equal(h['ras_good'], 1)
56+
assert_equal(h['goodRASFlag'], 1)
5757
assert_array_equal(h['dims'], [3, 4, 5, 2])
5858
assert_almost_equal(h['tr'], 2.0)
5959
assert_almost_equal(h['flip_angle'], 0.0)
@@ -87,7 +87,7 @@ def test_write_mgh():
8787
assert_equal(h['version'], 1)
8888
assert_equal(h['type'], 3)
8989
assert_equal(h['dof'], 0)
90-
assert_equal(h['ras_good'], 1)
90+
assert_equal(h['goodRASFlag'], 1)
9191
assert_array_equal(h['dims'], [5, 4, 3, 2])
9292
assert_almost_equal(h['tr'], 0.0)
9393
assert_almost_equal(h['flip_angle'], 0.0)
@@ -117,19 +117,16 @@ def test_write_noaffine_mgh():
117117
assert_equal(h['version'], 1)
118118
assert_equal(h['type'], 0) # uint8 for mgh
119119
assert_equal(h['dof'], 0)
120-
assert_equal(h['ras_good'], 1)
120+
assert_equal(h['goodRASFlag'], 1)
121121
assert_array_equal(h['dims'], [7, 13, 3, 22])
122122
assert_almost_equal(h['tr'], 0.0)
123123
assert_almost_equal(h['flip_angle'], 0.0)
124124
assert_almost_equal(h['te'], 0.0)
125125
assert_almost_equal(h['ti'], 0.0)
126126
assert_almost_equal(h['fov'], 0.0)
127127
# important part -- whether default affine info is stored
128-
assert_array_almost_equal(h['x_ras'].T, [[-1, 0, 0]])
129-
assert_array_almost_equal(h['y_ras'].T, [[0, 0, 1]])
130-
assert_array_almost_equal(h['z_ras'].T, [[0, -1, 0]])
131-
132-
assert_array_almost_equal(h['c_ras'].T, [[0, 0, 0]])
128+
assert_array_almost_equal(h['Mdc'], [[-1, 0, 0], [0, 0, 1], [0, -1, 0]])
129+
assert_array_almost_equal(h['Pxyz_c'], [0, 0, 0])
133130

134131

135132
def bad_dtype_mgh():
@@ -187,15 +184,14 @@ def test_header_updating():
187184
assert_almost_equal(mgz.affine, exp_aff, 6)
188185
assert_almost_equal(hdr.get_affine(), exp_aff, 6)
189186
# Test that initial wonky header elements have not changed
190-
assert_equal(hdr['voxelsize'], 1)
191-
assert_almost_equal(np.hstack((hdr['x_ras'], hdr['y_ras'], hdr['z_ras'])),
192-
exp_aff[:3, :3])
187+
assert_equal(hdr['delta'], 1)
188+
assert_almost_equal(hdr['Mdc'].T, exp_aff[:3, :3])
193189
# Save, reload, same thing
194190
img_fobj = io.BytesIO()
195191
mgz2 = _mgh_rt(mgz, img_fobj)
196192
hdr2 = mgz2.header
197193
assert_almost_equal(hdr2.get_affine(), exp_aff, 6)
198-
assert_equal(hdr2['voxelsize'], 1)
194+
assert_equal(hdr2['delta'], 1)
199195
# Change affine, change underlying header info
200196
exp_aff_d = exp_aff.copy()
201197
exp_aff_d[0, -1] = -14
@@ -204,10 +200,8 @@ def test_header_updating():
204200
mgz2.update_header()
205201
assert_almost_equal(hdr2.get_affine(), exp_aff_d, 6)
206202
RZS = exp_aff_d[:3, :3]
207-
assert_almost_equal(hdr2['voxelsize'], np.sqrt(np.sum(RZS ** 2, axis=0)))
208-
assert_almost_equal(
209-
np.hstack((hdr2['x_ras'], hdr2['y_ras'], hdr2['z_ras'])),
210-
RZS / hdr2['voxelsize'])
203+
assert_almost_equal(hdr2['delta'], np.sqrt(np.sum(RZS ** 2, axis=0)))
204+
assert_almost_equal(hdr2['Mdc'].T, RZS / hdr2['delta'])
211205

212206

213207
def test_cosine_order():
@@ -222,10 +216,8 @@ def test_cosine_order():
222216
hdr2 = img2.header
223217
RZS = aff[:3, :3]
224218
zooms = np.sqrt(np.sum(RZS ** 2, axis=0))
225-
assert_almost_equal(
226-
np.hstack((hdr2['x_ras'], hdr2['y_ras'], hdr2['z_ras'])),
227-
RZS / zooms)
228-
assert_almost_equal(hdr2['voxelsize'], zooms)
219+
assert_almost_equal(hdr2['Mdc'].T, RZS / zooms)
220+
assert_almost_equal(hdr2['delta'], zooms)
229221

230222

231223
def test_eq():
@@ -273,13 +265,11 @@ def test_mgh_reject_little_endian():
273265

274266
def test_mgh_affine_default():
275267
hdr = MGHHeader()
276-
hdr['ras_good'] = 0
268+
hdr['goodRASFlag'] = 0
277269
hdr2 = MGHHeader(hdr.binaryblock)
278-
assert_equal(hdr2['ras_good'], 1)
279-
assert_array_equal(hdr['x_ras'], hdr2['x_ras'])
280-
assert_array_equal(hdr['y_ras'], hdr2['y_ras'])
281-
assert_array_equal(hdr['z_ras'], hdr2['z_ras'])
282-
assert_array_equal(hdr['c_ras'], hdr2['c_ras'])
270+
assert_equal(hdr2['goodRASFlag'], 1)
271+
assert_array_equal(hdr['Mdc'], hdr2['Mdc'])
272+
assert_array_equal(hdr['Pxyz_c'], hdr2['Pxyz_c'])
283273

284274

285275
def test_mgh_set_data_shape():

0 commit comments

Comments
 (0)
Please sign in to comment.