1
1
from pathlib import Path
2
+ from unittest import skipUnless
2
3
3
4
import numpy as np
4
5
5
6
from nibabel import pointset as ps
6
7
from nibabel .arrayproxy import ArrayProxy
7
8
from nibabel .optpkg import optional_package
9
+ from nibabel .tests .nibabel_data import get_nibabel_data
8
10
9
11
h5 , has_h5py , _ = optional_package ('h5py' )
10
12
13
+ FS_DATA = Path (get_nibabel_data ()) / 'nitest-freesurfer'
14
+
11
15
12
16
class H5ArrayProxy :
13
17
def __init__ (self , file_like , dataset_name ):
@@ -38,7 +42,7 @@ def __array__(self, dtype=None):
38
42
with h5 .File (self .file_like , 'r' ) as h5f :
39
43
return np .asanyarray (h5f [self .dataset_name ], dtype )
40
44
41
- def __slicer__ (self , slicer ):
45
+ def __getitem__ (self , slicer ):
42
46
with h5 .File (self .file_like , 'r' ) as h5f :
43
47
return h5f [self .dataset_name ][slicer ]
44
48
@@ -48,19 +52,22 @@ class H5Geometry(ps.TriangularMesh):
48
52
with one or more coordinate sets
49
53
"""
50
54
55
+ def __init__ (self , meshes ):
56
+ self ._meshes = meshes
57
+
51
58
@classmethod
52
59
def from_filename (klass , pathlike ):
53
60
meshes = {}
54
61
with h5 .File (pathlike , 'r' ) as h5f :
55
- triangles = h5f [ ' topology']
56
- for name , coords in h5f ['coordinates' ]. items () :
57
- meshes [name ] = (coords , triangles )
62
+ triangles = H5ArrayProxy ( pathlike , '/ topology')
63
+ for name in h5f ['coordinates' ]:
64
+ meshes [name ] = (H5ArrayProxy ( pathlike , f'/coordinates/ { name } ' ) , triangles )
58
65
return klass (meshes )
59
66
60
67
def to_filename (self , pathlike ):
61
68
topology = None
62
69
coordinates = {}
63
- for name , mesh in self .meshes .items ():
70
+ for name , mesh in self ._meshes .items ():
64
71
coords , faces = mesh
65
72
if topology is None :
66
73
topology = faces
@@ -69,9 +76,9 @@ def to_filename(self, pathlike):
69
76
coordinates [name ] = coords
70
77
71
78
with h5 .File (pathlike , 'w' ) as h5f :
72
- h5f .create_dataset ('/topology' , topology )
79
+ h5f .create_dataset ('/topology' , data = topology )
73
80
for name , coord in coordinates .items ():
74
- h5f .create_dataset (f'/coordinates/{ name } ' , coord )
81
+ h5f .create_dataset (f'/coordinates/{ name } ' , data = coord )
75
82
76
83
def get_coords (self , name = None ):
77
84
if name is None :
@@ -139,6 +146,9 @@ def triangles(self):
139
146
140
147
141
148
class FreeSurferHemisphere (ps .TriangularMesh ):
149
+ def __init__ (self , meshes ):
150
+ self ._meshes = meshes
151
+
142
152
@classmethod
143
153
def from_filename (klass , pathlike ):
144
154
path = Path (pathlike )
@@ -176,8 +186,26 @@ def get_triangles(self, name=None):
176
186
177
187
@property
178
188
def n_coords (self ):
179
- return self .meshes [self ._default ].vnum
189
+ return self ._meshes [self ._default ].vnum
180
190
181
191
@property
182
192
def n_triangles (self ):
183
- return self .meshes [self ._default ].fnum
193
+ return self ._meshes [self ._default ].fnum
194
+
195
+
196
+ def test_FreeSurferHemisphere ():
197
+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
198
+ assert lh .n_coords == 163842
199
+ assert lh .n_triangles == 327680
200
+
201
+
202
+ @skipUnless (has_h5py , reason = 'Test requires h5py' )
203
+ def test_make_H5Geometry (tmp_path ):
204
+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
205
+ h5geo = H5Geometry ({name : lh .get_mesh (name ) for name in ('white' , 'pial' )})
206
+ h5geo .to_filename (tmp_path / 'geometry.h5' )
207
+
208
+ rt_h5geo = H5Geometry .from_filename (tmp_path / 'geometry.h5' )
209
+ assert set (h5geo ._meshes ) == set (rt_h5geo ._meshes )
210
+ assert np .array_equal (lh .get_coords ('white' ), rt_h5geo .get_coords ('white' ))
211
+ assert np .array_equal (lh .get_triangles (), rt_h5geo .get_triangles ())
0 commit comments