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: Alexandre Gramfort <alexandre.gramfort@inria.fr>
# Eric Larson <larson.eric.d@gmail.com>
# Oleh Kozynets <ok7mailbox@gmail.com>
# Guillaume Favelier <guillaume.favelier@gmail.com>
# jona-sassenhagen <jona.sassenhagen@gmail.com>
#
# License: Simplified BSD
from os import path as path
import numpy as np
from ...utils import (_check_option, get_subjects_dir, _check_fname,
_validate_type)
from ...surface import (complete_surface_info, read_surface, read_curvature,
_read_patch)
class _Surface(object):
"""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]) if x_dir is None else x_dir
assert isinstance(x_dir, np.ndarray)
assert np.isclose(np.linalg.norm(x_dir), 1., 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.grey_curv = None
self.nn = None
self.labels = dict()
self.x_dir = x_dir
subjects_dir = 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',
'%s.%s' % (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.
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', '%s.curv' % self.hemi)
self.curv = read_curvature(curv_path, binary=False)
self.bin_curv = np.array(self.curv > 0, np.int64)
# morphometry (curvature) normalization in order to get gray cortex
# TODO: delete self.grey_curv after cortex parameter
# will be fully supported
color = (self.curv > 0).astype(float)
color = 0.5 - (color - 0.5) / 3
color = color[:, np.newaxis] * [1, 1, 1]
self.grey_curv = color
|