[074d3d]: / mne / viz / _brain / surface.py

Download this file

178 lines (158 with data), 5.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
from os import path as path
import numpy as np
from ...surface import _read_patch, complete_surface_info, read_curvature, read_surface
from ...utils import _check_fname, _check_option, _validate_type, get_subjects_dir
class _Surface:
"""Container for a brain surface.
It is used for storing vertices, faces and morphometric data
(curvature) of a hemisphere mesh.
Parameters
----------
subject : string
Name of subject
hemi : {'lh', 'rh'}
Which hemisphere to load
surf : string
Name of the surface to load (eg. inflated, orig ...).
subjects_dir : str | None
If not None, this directory will be used as the subjects directory
instead of the value set using the SUBJECTS_DIR environment variable.
offset : float | None
If 0.0, the surface will be offset such that the medial
wall is aligned with the origin. If None, no offset will
be applied. If != 0.0, an additional offset will be used.
units : str
Can be 'm' or 'mm' (default).
x_dir : ndarray | None
The x direction to use for offset alignment.
Attributes
----------
bin_curv : numpy.ndarray
Curvature values stored as non-negative integers.
coords : numpy.ndarray
nvtx x 3 array of vertex (x, y, z) coordinates.
curv : numpy.ndarray
Vector representation of surface morpometry (curvature) values as
loaded from a file.
grey_curv : numpy.ndarray
Normalized morphometry (curvature) data, used in order to get
a gray cortex.
faces : numpy.ndarray
nfaces x 3 array of defining mesh triangles.
hemi : {'lh', 'rh'}
Which hemisphere to load.
nn : numpy.ndarray
Vertex normals for a triangulated surface.
offset : float | None
If float, align inside edge of each hemisphere to center + offset.
If None, do not change coordinates (default).
subject : string
Name of subject.
surf : string
Name of the surface to load (eg. inflated, orig ...).
units : str
Can be 'm' or 'mm' (default).
"""
def __init__(
self,
subject,
hemi,
surf,
subjects_dir=None,
offset=None,
units="mm",
x_dir=None,
):
x_dir = np.array([1.0, 0, 0]) if x_dir is None else x_dir
assert isinstance(x_dir, np.ndarray)
assert np.isclose(np.linalg.norm(x_dir), 1.0, atol=1e-6)
assert hemi in ("lh", "rh")
_validate_type(offset, (None, "numeric"), "offset")
self.units = _check_option("units", units, ("mm", "m"))
self.subject = subject
self.hemi = hemi
self.surf = surf
self.offset = offset
self.bin_curv = None
self.coords = None
self.curv = None
self.faces = None
self.nn = None
self.labels = dict()
self.x_dir = x_dir
subjects_dir = str(get_subjects_dir(subjects_dir, raise_error=True))
self.data_path = path.join(subjects_dir, subject)
if surf == "seghead":
raise ValueError(
"`surf` cannot be seghead, use "
"`mne.viz.Brain.add_head` to plot the seghead"
)
def load_geometry(self):
"""Load geometry of the surface.
Parameters
----------
None
Returns
-------
None
"""
if self.surf == "flat": # special case
fname = path.join(self.data_path, "surf", f"{self.hemi}.cortex.patch.flat")
_check_fname(
fname, overwrite="read", must_exist=True, name="flatmap surface file"
)
coords, faces, orig_faces = _read_patch(fname)
# rotate 90 degrees to get to a more standard orientation
# where X determines the distance between the hemis
coords = coords[:, [1, 0, 2]]
coords[:, 1] *= -1
else:
# allow ?h.pial.T1 if ?h.pial doesn't exist for instance
# end with '' for better file not found error
for img in ("", ".T1", ".T2", ""):
surf_fname = path.join(
self.data_path, "surf", f"{self.hemi}.{self.surf}{img}"
)
if path.isfile(surf_fname):
break
coords, faces = read_surface(surf_fname)
orig_faces = faces
if self.units == "m":
coords /= 1000.0
if self.offset is not None:
x_ = coords @ self.x_dir
if self.hemi == "lh":
coords -= (np.max(x_) + self.offset) * self.x_dir
else:
coords -= (np.min(x_) + self.offset) * self.x_dir
surf = dict(rr=coords, tris=faces)
complete_surface_info(surf, copy=False, verbose=False, do_neighbor_tri=False)
nn = surf["nn"]
self.coords = coords
self.faces = faces
self.orig_faces = orig_faces
self.nn = nn
def __len__(self):
"""Return number of vertices."""
return len(self.coords)
@property
def x(self):
return self.coords[:, 0]
@property
def y(self):
return self.coords[:, 1]
@property
def z(self):
return self.coords[:, 2]
def load_curvature(self):
"""Load in curvature values from the ?h.curv file."""
curv_path = path.join(self.data_path, "surf", f"{self.hemi}.curv")
if path.isfile(curv_path):
self.curv = read_curvature(curv_path, binary=False)
self.bin_curv = np.array(self.curv > 0, np.int64)
else:
self.curv = None
self.bin_curv = None