针对pulse-transit的工具
This commit is contained in:
123
dist/client/mne/io/artemis123/utils.py
vendored
Normal file
123
dist/client/mne/io/artemis123/utils.py
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
# Authors: The MNE-Python contributors.
|
||||
# License: BSD-3-Clause
|
||||
# Copyright the MNE-Python contributors.
|
||||
|
||||
import os.path as op
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..._fiff._digitization import _artemis123_read_pos
|
||||
from ...transforms import rotation3d_align_z_axis
|
||||
from ...utils import logger
|
||||
|
||||
|
||||
def _load_mne_locs(fname=None):
|
||||
"""Load MNE locs structure from file (if exists) or recreate it."""
|
||||
if not fname:
|
||||
# find input file
|
||||
resource_dir = op.join(op.dirname(op.abspath(__file__)), "resources")
|
||||
fname = op.join(resource_dir, "Artemis123_mneLoc.csv")
|
||||
|
||||
if not op.exists(fname):
|
||||
raise OSError(f'MNE locs file "{fname}" does not exist')
|
||||
|
||||
logger.info(f"Loading mne loc file {fname}")
|
||||
locs = dict()
|
||||
with open(fname) as fid:
|
||||
for line in fid:
|
||||
vals = line.strip().split(",")
|
||||
locs[vals[0]] = np.array(vals[1::], np.float64)
|
||||
|
||||
return locs
|
||||
|
||||
|
||||
def _generate_mne_locs_file(output_fname):
|
||||
"""Generate mne coil locs and save to supplied file."""
|
||||
logger.info("Converting Tristan coil file to mne loc file...")
|
||||
resource_dir = op.join(op.dirname(op.abspath(__file__)), "resources")
|
||||
chan_fname = op.join(resource_dir, "Artemis123_ChannelMap.csv")
|
||||
chans = _load_tristan_coil_locs(chan_fname)
|
||||
|
||||
# compute a dict of loc structs
|
||||
locs = {n: _compute_mne_loc(cinfo) for n, cinfo in chans.items()}
|
||||
|
||||
# write it out to output_fname
|
||||
with open(output_fname, "w") as fid:
|
||||
for n in sorted(locs.keys()):
|
||||
fid.write(f"{n},")
|
||||
fid.write(",".join(locs[n].astype(str)))
|
||||
fid.write("\n")
|
||||
|
||||
|
||||
def _load_tristan_coil_locs(coil_loc_path):
|
||||
"""Load the Coil locations from Tristan CAD drawings."""
|
||||
channel_info = dict()
|
||||
with open(coil_loc_path) as fid:
|
||||
# skip 2 Header lines
|
||||
fid.readline()
|
||||
fid.readline()
|
||||
for line in fid:
|
||||
line = line.strip()
|
||||
vals = line.split(",")
|
||||
channel_info[vals[0]] = dict()
|
||||
if vals[6]:
|
||||
channel_info[vals[0]]["inner_coil"] = np.array(vals[2:5], np.float64)
|
||||
channel_info[vals[0]]["outer_coil"] = np.array(vals[5:8], np.float64)
|
||||
else: # nothing supplied
|
||||
channel_info[vals[0]]["inner_coil"] = np.zeros(3)
|
||||
channel_info[vals[0]]["outer_coil"] = np.zeros(3)
|
||||
return channel_info
|
||||
|
||||
|
||||
def _compute_mne_loc(coil_loc):
|
||||
"""Convert a set of coils to an mne Struct.
|
||||
|
||||
Note input coil locations are in inches.
|
||||
"""
|
||||
loc = np.zeros(12)
|
||||
if (np.linalg.norm(coil_loc["inner_coil"]) == 0) and (
|
||||
np.linalg.norm(coil_loc["outer_coil"]) == 0
|
||||
):
|
||||
return loc
|
||||
|
||||
# channel location is inner coil location converted to meters From inches
|
||||
loc[0:3] = coil_loc["inner_coil"] / 39.370078
|
||||
|
||||
# figure out rotation
|
||||
z_axis = coil_loc["outer_coil"] - coil_loc["inner_coil"]
|
||||
R = rotation3d_align_z_axis(z_axis)
|
||||
loc[3:13] = R.T.reshape(9)
|
||||
return loc
|
||||
|
||||
|
||||
def _read_pos(fname):
|
||||
"""Read the .pos file and return positions as dig points."""
|
||||
nas, lpa, rpa, hpi, extra = None, None, None, None, None
|
||||
with open(fname) as fid:
|
||||
for line in fid:
|
||||
line = line.strip()
|
||||
if len(line) > 0:
|
||||
parts = line.split()
|
||||
# The lines can have 4 or 5 parts. First part is for the id,
|
||||
# which can be an int or a string. The last three are for xyz
|
||||
# coordinates. The extra part is for additional info
|
||||
# (e.g. 'Pz', 'Cz') which is ignored.
|
||||
if len(parts) not in [4, 5]:
|
||||
continue
|
||||
|
||||
if parts[0].lower() == "nasion":
|
||||
nas = np.array([float(p) for p in parts[-3:]]) / 100.0
|
||||
elif parts[0].lower() == "left":
|
||||
lpa = np.array([float(p) for p in parts[-3:]]) / 100.0
|
||||
elif parts[0].lower() == "right":
|
||||
rpa = np.array([float(p) for p in parts[-3:]]) / 100.0
|
||||
elif "hpi" in parts[0].lower():
|
||||
if hpi is None:
|
||||
hpi = list()
|
||||
hpi.append(np.array([float(p) for p in parts[-3:]]) / 100.0)
|
||||
else:
|
||||
if extra is None:
|
||||
extra = list()
|
||||
extra.append(np.array([float(p) for p in parts[-3:]]) / 100.0)
|
||||
|
||||
return _artemis123_read_pos(nas, lpa, rpa, hpi, extra)
|
||||
Reference in New Issue
Block a user