12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- """
- Python Library to Read Surface Files in Freesurfer's TriangularSurface Format
- compatible with Freesurfer's MRISwriteTriangularSurface()
- https://github.com/freesurfer/freesurfer/blob/release_6_0_0/include/mrisurf.h#L1281
- https://github.com/freesurfer/freesurfer/blob/release_6_0_0/utils/mrisurf.c
- https://raw.githubusercontent.com/freesurfer/freesurfer/release_6_0_0/utils/mrisurf.c
- Freesurfer
- https://surfer.nmr.mgh.harvard.edu/
- >>> from freesurfer_surface import Surface
- >>>
- >>> surface = Surface.read_triangular('bert/surf/lh.pial'))
- """
- import collections
- import re
- import struct
- import typing
- try:
- from freesurfer_surface.version import __version__
- except ImportError:
- __version__ = None
- Vertex = collections.namedtuple('Vertex', ['right', 'anterior', 'superior'])
- class Surface:
- _MAGIC_NUMBER = b'\xff\xff\xfe'
- _TAG_CMDLINE = b'\x00\x00\x00\x03'
- _TAG_OLD_SURF_GEOM = b'\x00\x00\x00\x14'
- _TAG_OLD_USEREALRAS = b'\x00\x00\x00\x02'
- def __init__(self):
- self.creator = None
- self.vertices = []
- self.triangles_vertex_indices = []
-
- self.using_old_real_ras = False
- self.volume_geometry_info = None
- self.command_lines = []
- @classmethod
- def _read_cmdlines(cls, stream: typing.BinaryIO) -> typing.Iterator[str]:
- while True:
- tag = stream.read(4)
- if not tag:
- return
- assert tag == cls._TAG_CMDLINE
-
-
- str_length, = struct.unpack('>Q', stream.read(8))
- yield stream.read(str_length - 1)
- assert stream.read(1) == b'\x00'
- def _read_triangular(self, stream: typing.BinaryIO):
- assert stream.read(3) == self._MAGIC_NUMBER
- self.creator = re.match(rb'^created by (\w+) on .* \d{4}\n',
- stream.readline()).groups()
- assert stream.read(1) == b'\n'
-
-
- vertices_num, triangles_num = struct.unpack('>II', stream.read(4 * 2))
- self.vertices = [Vertex(*struct.unpack('>fff', stream.read(4 * 3)))
- for _ in range(vertices_num)]
- self.triangles_vertex_indices = [struct.unpack('>III', stream.read(4 * 3))
- for _ in range(triangles_num)]
- assert all(vertex_idx < vertices_num
- for triangle_vertex_index in self.triangles_vertex_indices
- for vertex_idx in triangle_vertex_index)
- assert stream.read(4) == self._TAG_OLD_USEREALRAS
- using_old_real_ras, = struct.unpack('>I', stream.read(4))
- assert using_old_real_ras in [0, 1], using_old_real_ras
- self.using_old_real_ras = bool(using_old_real_ras)
- assert stream.read(4) == self._TAG_OLD_SURF_GEOM
-
-
- self.volume_geometry_info = [stream.readline() for _ in range(8)]
- self.command_lines = list(self._read_cmdlines(stream))
- @classmethod
- def read_triangular(cls, surface_file_path: str) -> 'Surface':
- surface = cls()
- with open(surface_file_path, 'rb') as surface_file:
-
- surface._read_triangular(surface_file)
- return surface
|