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
@@ -47,19 +51,22 @@ class H5Geometry(ps.TriangularMesh):
47
51
"""Simple Geometry file structure that combines a single topology
48
52
with one or more coordinate sets
49
53
"""
54
+ def __init__ (self , meshes ):
55
+ self ._meshes = meshes
56
+
50
57
@classmethod
51
58
def from_filename (klass , pathlike ):
52
59
meshes = {}
53
60
with h5 .File (pathlike , "r" ) as h5f :
54
- triangles = h5f [ ' topology']
55
- for name , coords in h5f ['coordinates' ]. items () :
56
- meshes [name ] = (coords , triangles )
61
+ triangles = H5ArrayProxy ( pathlike , '/ topology')
62
+ for name in h5f ['coordinates' ]:
63
+ meshes [name ] = (H5ArrayProxy ( pathlike , f'/coordinates/ { name } ' ) , triangles )
57
64
return klass (meshes )
58
65
59
66
def to_filename (self , pathlike ):
60
67
topology = None
61
68
coordinates = {}
62
- for name , mesh in self .meshes .items ():
69
+ for name , mesh in self ._meshes .items ():
63
70
coords , faces = mesh
64
71
if topology is None :
65
72
topology = faces
@@ -68,9 +75,9 @@ def to_filename(self, pathlike):
68
75
coordinates [name ] = coords
69
76
70
77
with h5 .File (pathlike , "w" ) as h5f :
71
- h5f .create_dataset ("/topology" , topology )
78
+ h5f .create_dataset ("/topology" , data = topology )
72
79
for name , coord in coordinates .items ():
73
- h5f .create_dataset (f"/coordinates/{ name } " , coord )
80
+ h5f .create_dataset (f"/coordinates/{ name } " , data = coord )
74
81
75
82
def get_coords (self , name = None ):
76
83
if name is None :
@@ -137,6 +144,9 @@ def triangles(self):
137
144
138
145
139
146
class FreeSurferHemisphere (ps .TriangularMesh ):
147
+ def __init__ (self , meshes ):
148
+ self ._meshes = meshes
149
+
140
150
@classmethod
141
151
def from_filename (klass , pathlike ):
142
152
path = Path (pathlike )
@@ -167,8 +177,26 @@ def get_triangles(self, name=None):
167
177
168
178
@property
169
179
def n_coords (self ):
170
- return self .meshes [self ._default ].vnum
180
+ return self ._meshes [self ._default ].vnum
171
181
172
182
@property
173
183
def n_triangles (self ):
174
- return self .meshes [self ._default ].fnum
184
+ return self ._meshes [self ._default ].fnum
185
+
186
+
187
+ def test_FreeSurferHemisphere ():
188
+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
189
+ assert lh .n_coords == 163842
190
+ assert lh .n_triangles == 327680
191
+
192
+
193
+ @skipUnless (has_h5py , reason = "Test requires h5py" )
194
+ def test_make_H5Geometry (tmp_path ):
195
+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
196
+ h5geo = H5Geometry ({name : lh .get_mesh (name ) for name in ('white' , 'pial' )})
197
+ h5geo .to_filename (tmp_path / "geometry.h5" )
198
+
199
+ rt_h5geo = H5Geometry .from_filename (tmp_path / "geometry.h5" )
200
+ assert set (h5geo ._meshes ) == set (rt_h5geo ._meshes )
201
+ assert np .array_equal (lh .get_coords ('white' ), rt_h5geo .get_coords ('white' ))
202
+ assert np .array_equal (lh .get_triangles (), rt_h5geo .get_triangles ())
0 commit comments