Skip to content

Commit 880152a

Browse files
committed
Changed from strings to np.arrays. Allow head == 20.
1 parent b5f1849 commit 880152a

File tree

2 files changed

+54
-30
lines changed

2 files changed

+54
-30
lines changed

nibabel/freesurfer/io.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,26 @@ def _fread3_many(fobj, n):
4747

4848
def _read_volume_info(fobj):
4949
volume_info = OrderedDict()
50-
head = np.fromfile(fobj, '>i4', 3)
51-
if any(head != [2, 0, 20]):
52-
warnings.warn("Unknown extension code.")
53-
else:
54-
volume_info['head'] = head
55-
for key in ['valid', 'filename', 'volume', 'voxelsize', 'xras', 'yras',
56-
'zras', 'cras']:
57-
pair = fobj.readline().decode('utf-8').split('=')
58-
if pair[0].strip() != key or len(pair) != 2:
59-
raise IOError('Error parsing volume info.')
60-
volume_info[pair[0]] = pair[1]
61-
# Ignore the rest
50+
head = np.fromfile(fobj, '>i4', 1)
51+
if not np.array_equal(head, [20]): # Read two bytes more
52+
head = np.concatenate([head, np.fromfile(fobj, '>i4', 2)])
53+
if not np.array_equal(head, [2, 0, 20]):
54+
warnings.warn("Unknown extension code.")
55+
return volume_info
56+
57+
volume_info['head'] = head
58+
for key in ['valid', 'filename', 'volume', 'voxelsize', 'xras', 'yras',
59+
'zras', 'cras']:
60+
pair = fobj.readline().decode('utf-8').split('=')
61+
if pair[0].strip() != key or len(pair) != 2:
62+
raise IOError('Error parsing volume info.')
63+
if key in ('valid', 'filename'):
64+
volume_info[key] = pair[1].strip()
65+
elif key == 'volume':
66+
volume_info[key] = np.array(pair[1].split()).astype(int)
67+
else:
68+
volume_info[key] = np.array(pair[1].split()).astype(float)
69+
# Ignore the rest
6270
return volume_info
6371

6472

@@ -122,14 +130,17 @@ def read_geometry(filepath, read_metadata=False, read_stamp=False):
122130
coords = np.fromfile(fobj, ">f4", vnum * 3).reshape(vnum, 3)
123131
faces = np.fromfile(fobj, ">i4", fnum * 3).reshape(fnum, 3)
124132

125-
volume_info = _read_volume_info(fobj)
133+
if read_metadata:
134+
volume_info = _read_volume_info(fobj)
126135
else:
127136
raise ValueError("File does not appear to be a Freesurfer surface")
128137

129138
coords = coords.astype(np.float) # XXX: due to mayavi bug on mac 32bits
130139

131140
ret = (coords, faces)
132141
if read_metadata:
142+
if len(volume_info) == 0:
143+
warnings.warn('No volume information contained in the file')
133144
ret += (volume_info,)
134145
if read_stamp:
135146
ret += (create_stamp,)
@@ -174,9 +185,15 @@ def write_geometry(filepath, coords, faces, create_stamp=None,
174185
if volume_info is not None and len(volume_info) > 0:
175186
for key, val in volume_info.items():
176187
if key == 'head':
177-
val.tofile(fobj)
178-
continue
179-
fobj.write('{0}={1}'.format(key, val).encode('utf-8'))
188+
np.array(val, dtype='>i4').tofile(fobj)
189+
elif key in ('valid', 'filename'):
190+
fobj.write('{0} = {1}\n'.format(key, val).encode('utf-8'))
191+
elif key == 'volume':
192+
fobj.write('{0} = {1} {2} {3}\n'.format(
193+
key, val[0], val[1], val[2]).encode('utf-8'))
194+
else:
195+
fobj.write('{0} = {1:.4f} {2:.4f} {3:.4f}\n'.format(
196+
key.ljust(6), val[0], val[1], val[2]).encode('utf-8'))
180197

181198

182199
def read_morph_data(filepath):

nibabel/freesurfer/tests/test_io.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,43 @@ def test_geometry():
5555
assert_equal(0, faces.min())
5656
assert_equal(coords.shape[0], faces.max() + 1)
5757

58-
# Test quad with sphere
59-
with clear_and_catch_warnings():
60-
warnings.filterwarnings('always', category=DeprecationWarning)
61-
surf_path = pjoin(data_path, "surf", "%s.%s" % ("lh", "sphere"))
62-
coords, faces, volume_info, create_stamp = \
63-
read_geometry(surf_path, read_metadata=True, read_stamp=True)
64-
assert_equal(0, faces.min())
65-
assert_equal(coords.shape[0], faces.max() + 1)
66-
assert_equal(9, len(volume_info))
67-
assert_equal([2, 0, 20], volume_info['head'])
68-
assert_equal(u'created by greve on Thu Jun 8 19:17:51 2006',
69-
create_stamp)
58+
surf_path = pjoin(data_path, "surf", "%s.%s" % ("lh", "sphere"))
59+
warnings.filterwarnings('always', category=DeprecationWarning)
60+
coords, faces, volume_info, create_stamp = read_geometry(
61+
surf_path, read_metadata=True, read_stamp=True)
62+
63+
assert_equal(0, faces.min())
64+
assert_equal(coords.shape[0], faces.max() + 1)
65+
assert_equal(9, len(volume_info))
66+
assert_equal([2, 0, 20], volume_info['head'])
67+
assert_equal(u'created by greve on Thu Jun 8 19:17:51 2006',
68+
create_stamp)
7069

7170
# Test equivalence of freesurfer- and nibabel-generated triangular files
7271
# with respect to read_geometry()
7372
with InTemporaryDirectory():
7473
surf_path = 'test'
7574
create_stamp = "created by %s on %s" % (getpass.getuser(),
7675
time.ctime())
77-
volume_info['cras '] = '1. 2. 3.'
76+
volume_info['cras'] = [1., 2., 3.]
7877
write_geometry(surf_path, coords, faces, create_stamp, volume_info)
7978

8079
coords2, faces2, volume_info2 = \
8180
read_geometry(surf_path, read_metadata=True)
8281

83-
assert_equal(volume_info2['cras '], volume_info['cras '])
82+
assert_equal(volume_info2['cras'], volume_info['cras'])
8483
with open(surf_path, 'rb') as fobj:
8584
np.fromfile(fobj, ">u1", 3)
8685
read_create_stamp = fobj.readline().decode().rstrip('\n')
8786

87+
# now write an incomplete file
88+
write_geometry(surf_path, coords, faces)
89+
with clear_and_catch_warnings() as w:
90+
warnings.filterwarnings('always', category=DeprecationWarning)
91+
read_geometry(surf_path, read_metadata=True)
92+
assert_true(any('volume information contained' in str(ww.message)
93+
for ww in w))
94+
8895
assert_equal(create_stamp, read_create_stamp)
8996

9097
np.testing.assert_array_equal(coords, coords2)

0 commit comments

Comments
 (0)