@@ -40,105 +40,6 @@ def _get_subjects_dir(subjects_dir=None):
40
40
return subjects_dir
41
41
42
42
43
- def _fread3 (fobj ):
44
- """Read a 3-byte int from an open binary file object."""
45
- b1 , b2 , b3 = np .fromfile (fobj , ">u1" , 3 )
46
- return (b1 << 16 ) + (b2 << 8 ) + b3
47
-
48
-
49
- def _fread3_many (fobj , n ):
50
- """Read 3-byte ints from an open binary file object."""
51
- b1 , b2 , b3 = np .fromfile (fobj , ">u1" , 3 * n ).reshape (- 1 ,
52
- 3 ).astype (np .int ).T
53
- return (b1 << 16 ) + (b2 << 8 ) + b3
54
-
55
-
56
- def read_geometry (filepath ):
57
- """Read a triangular format Freesurfer surface mesh.
58
-
59
- Parameters
60
- ----------
61
- filepath : str
62
- Path to surface file
63
-
64
- Returns
65
- -------
66
- coords : numpy array
67
- nvtx x 3 array of vertex (x, y, z) coordinates
68
- faces : numpy array
69
- nfaces x 3 array of defining mesh triangles
70
- """
71
- with open (filepath , "rb" ) as fobj :
72
- magic = _fread3 (fobj )
73
- if magic == 16777215 : # Quad file
74
- nvert = _fread3 (fobj )
75
- nquad = _fread3 (fobj )
76
- coords = np .fromfile (fobj , ">i2" , nvert * 3 ).astype (np .float )
77
- coords = coords .reshape (- 1 , 3 ) / 100.0
78
- quads = _fread3_many (fobj , nquad * 4 )
79
- quads = quads .reshape (nquad , 4 )
80
- #
81
- # Face splitting follows
82
- #
83
- faces = np .zeros ((2 * nquad , 3 ), dtype = np .int )
84
- nface = 0
85
- for quad in quads :
86
- if (quad [0 ] % 2 ) == 0 :
87
- faces [nface ] = quad [0 ], quad [1 ], quad [3 ]
88
- nface += 1
89
- faces [nface ] = quad [2 ], quad [3 ], quad [1 ]
90
- nface += 1
91
- else :
92
- faces [nface ] = quad [0 ], quad [1 ], quad [2 ]
93
- nface += 1
94
- faces [nface ] = quad [0 ], quad [2 ], quad [3 ]
95
- nface += 1
96
-
97
- elif magic == 16777214 : # Triangle file
98
- create_stamp = fobj .readline ()
99
- _ = fobj .readline ()
100
- vnum = np .fromfile (fobj , ">i4" , 1 )[0 ]
101
- fnum = np .fromfile (fobj , ">i4" , 1 )[0 ]
102
- coords = np .fromfile (fobj , ">f4" , vnum * 3 ).reshape (vnum , 3 )
103
- faces = np .fromfile (fobj , ">i4" , fnum * 3 ).reshape (fnum , 3 )
104
- else :
105
- raise ValueError ("File does not appear to be a Freesurfer surface" )
106
-
107
- coords = coords .astype (np .float ) # XXX: due to mayavi bug on mac 32bits
108
- return coords , faces
109
-
110
-
111
- def read_morph_data (filepath ):
112
- """Read a Freesurfer morphometry data file.
113
-
114
- This function reads in what Freesurfer internally calls "curv" file types,
115
- (e.g. ?h. curv, ?h.thickness), but as that has the potential to cause
116
- confusion where "curv" also refers to the surface curvature values,
117
- we refer to these files as "morphometry" files with PySurfer.
118
-
119
- Parameters
120
- ----------
121
- filepath : str
122
- Path to morphometry file
123
-
124
- Returns
125
- -------
126
- curv : numpy array
127
- Vector representation of surface morpometry values
128
-
129
- """
130
- with open (filepath , "rb" ) as fobj :
131
- magic = _fread3 (fobj )
132
- if magic == 16777215 :
133
- vnum = np .fromfile (fobj , ">i4" , 3 )[0 ]
134
- curv = np .fromfile (fobj , ">f4" , vnum )
135
- else :
136
- vnum = magic
137
- _ = _fread3 (fobj )
138
- curv = np .fromfile (fobj , ">i2" , vnum ) / 100
139
- return curv
140
-
141
-
142
43
def read_scalar_data (filepath ):
143
44
"""Load in scalar data from an image.
144
45
@@ -199,76 +100,6 @@ def read_scalar_data(filepath):
199
100
return scalar_data
200
101
201
102
202
- def read_annot (filepath , orig_ids = False ):
203
- """Read in a Freesurfer annotation from a .annot file.
204
-
205
- Parameters
206
- ----------
207
- filepath : str
208
- Path to annotation file
209
- orig_ids : bool
210
- Whether to return the vertex ids as stored in the annotation
211
- file or the positional colortable ids
212
-
213
- Returns
214
- -------
215
- labels : n_vtx numpy array
216
- Annotation id at each vertex
217
- ctab : numpy array
218
- RGBA + label id colortable array
219
- names : numpy array
220
- Array of region names as stored in the annot file
221
-
222
- """
223
- with open (filepath , "rb" ) as fobj :
224
- dt = ">i4"
225
- vnum = np .fromfile (fobj , dt , 1 )[0 ]
226
- data = np .fromfile (fobj , dt , vnum * 2 ).reshape (vnum , 2 )
227
- labels = data [:, 1 ]
228
- ctab_exists = np .fromfile (fobj , dt , 1 )[0 ]
229
- if not ctab_exists :
230
- raise Exception ('Color table not found in annotation file' )
231
- n_entries = np .fromfile (fobj , dt , 1 )[0 ]
232
- if n_entries > 0 :
233
- length = np .fromfile (fobj , dt , 1 )[0 ]
234
- orig_tab = np .fromfile (fobj , '>c' , length )
235
- orig_tab = orig_tab [:- 1 ]
236
-
237
- names = list ()
238
- ctab = np .zeros ((n_entries , 5 ), np .int )
239
- for i in xrange (n_entries ):
240
- name_length = np .fromfile (fobj , dt , 1 )[0 ]
241
- name = np .fromfile (fobj , "|S%d" % name_length , 1 )[0 ]
242
- names .append (name )
243
- ctab [i , :4 ] = np .fromfile (fobj , dt , 4 )
244
- ctab [i , 4 ] = (ctab [i , 0 ] + ctab [i , 1 ] * (2 ** 8 ) +
245
- ctab [i , 2 ] * (2 ** 16 ) +
246
- ctab [i , 3 ] * (2 ** 24 ))
247
- else :
248
- ctab_version = - n_entries
249
- if ctab_version != 2 :
250
- raise Exception ('Color table version not supported' )
251
- n_entries = np .fromfile (fobj , dt , 1 )[0 ]
252
- ctab = np .zeros ((n_entries , 5 ), np .int )
253
- length = np .fromfile (fobj , dt , 1 )[0 ]
254
- _ = np .fromfile (fobj , "|S%d" % length , 1 )[0 ] # Orig table path
255
- entries_to_read = np .fromfile (fobj , dt , 1 )[0 ]
256
- names = list ()
257
- for i in xrange (entries_to_read ):
258
- _ = np .fromfile (fobj , dt , 1 )[0 ] # Structure
259
- name_length = np .fromfile (fobj , dt , 1 )[0 ]
260
- name = np .fromfile (fobj , "|S%d" % name_length , 1 )[0 ]
261
- names .append (name )
262
- ctab [i , :4 ] = np .fromfile (fobj , dt , 4 )
263
- ctab [i , 4 ] = (ctab [i , 0 ] + ctab [i , 1 ] * (2 ** 8 ) +
264
- ctab [i , 2 ] * (2 ** 16 ))
265
- ctab [:, 3 ] = 255
266
- if not orig_ids :
267
- ord = np .argsort (ctab [:, - 1 ])
268
- labels = ord [np .searchsorted (ctab [ord , - 1 ], labels )]
269
- return labels , ctab , names
270
-
271
-
272
103
def read_label (filepath , read_scalars = False ):
273
104
"""Load in a Freesurfer .label file.
274
105
@@ -492,7 +323,12 @@ def __init__(self, subject_id, hemi, surf, subjects_dir=None):
492
323
def load_geometry (self ):
493
324
surf_path = pjoin (self .data_path , "surf" ,
494
325
"%s.%s" % (self .hemi , self .surf ))
495
- self .coords , self .faces = read_geometry (surf_path )
326
+ self .coords , self .faces = nib .freesurfer .read_geometry (surf_path )
327
+
328
+ def save_geometry (self ):
329
+ surf_path = pjoin (self .data_path , "surf" ,
330
+ "%s.%s" % (self .hemi , self .surf ))
331
+ nib .freesurfer .write_geometry (surf_path , self .coords , self .faces )
496
332
497
333
@property
498
334
def x (self ):
@@ -509,7 +345,7 @@ def z(self):
509
345
def load_curvature (self ):
510
346
"""Load in curvature values from the ?h.curv file."""
511
347
curv_path = pjoin (self .data_path , "surf" , "%s.curv" % self .hemi )
512
- self .curv = read_morph_data (curv_path )
348
+ self .curv = nib . freesurfer . read_morph_data (curv_path )
513
349
self .bin_curv = np .array (self .curv > 0 , np .int )
514
350
515
351
def load_label (self , name ):
@@ -521,8 +357,8 @@ def load_label(self, name):
521
357
argument.
522
358
523
359
"""
524
- label = read_label (pjoin (self .data_path , 'label' ,
525
- '%s.%s.label' % (self .hemi , name )))
360
+ label = nib . freesurfer . read_label (pjoin (self .data_path , 'label' ,
361
+ '%s.%s.label' % (self .hemi , name )))
526
362
label_array = np .zeros (len (self .x ), np .int )
527
363
label_array [label ] = 1
528
364
try :
0 commit comments