Last active
June 1, 2026 16:09
-
-
Save larsoner/5af20934521278927c8a3056df2bcb69 to your computer and use it in GitHub Desktop.
fsaverage_1005 code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| % Create fsaverage_1020 | |
| headshape = ft_read_headshape('~/mne_data/MNE-sample-data/subjects/fsaverage/bem/outer_skin.surf'); | |
| % [pos, tri, magic] = read_surf('~/mne_data/MNE-sample-data/subjects/fsaverage/surf/lh.seghead'); | |
| % headshape = []; | |
| % headshape.pos = pos; | |
| % headshape.tri = tri; | |
| % ft_plot_mesh(headshape,'facecolor','skin');camlight; | |
| assert(headshape.unit == "mm"); | |
| cfg = []; | |
| cfg.method = '1020'; | |
| cfg.coordsys = 'rpa'; | |
| cfg.fiducial = []; | |
| cfg.fiducial.lpa = [-80.61611938476562, -29.08875274658203, -41.310768127441406]; | |
| cfg.fiducial.nas = [1.467630386352539, 85.06715393066406, -34.83611297607422]; | |
| cfg.fiducial.rpa = [84.36284637451172, -28.502763748168945, -41.277435302734375]; | |
| cfg.fiducial.ini = [2.2790975635871296, -142.6586769521236, -47.75208979845047]; | |
| elec = ft_electrodeplacement(cfg, headshape); | |
| assert(elec.unit == "mm"); | |
| out_path = '~/python/mne-python/mne/channels/data/montages/fsaverage_1005.tsv'; | |
| C = [elec.label, num2cell(elec.elecpos * 1e-3)]; | |
| C = [{"label", "x", "y", "z"}; C]; | |
| writecell(C, out_path, 'filetype', 'text', 'delimiter', '\t'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from pathlib import Path | |
| import numpy as np | |
| import pandas as pd | |
| import mne | |
| from mne.io.constants import FIFF | |
| fids_fif = mne.coreg.get_mni_fiducials("fsaverage") | |
| fids = dict( | |
| lpa=fids_fif[0], | |
| nasion=fids_fif[1], | |
| rpa=fids_fif[2], | |
| ) | |
| for key, val in fids.items(): | |
| assert val["ident"] == getattr(FIFF, f"FIFFV_POINT_{key.upper()}") | |
| fids = {key: val["r"] for key, val in fids.items()} | |
| mri_head_t = mne.transforms._get_trans(trans="fsaverage", fro="mri", to="head")[0] | |
| fids_head = {key: mne.transforms.apply_trans(mri_head_t, fids[key]) for key in fids} | |
| np.testing.assert_allclose(fids_head["lpa"][2:], 0, atol=1e-6) | |
| assert -0.1 < fids_head["lpa"][0] < -0.01 # to the left | |
| np.testing.assert_allclose(fids_head["nasion"][[0, 2]], 0, atol=1e-6) | |
| assert 0.2 > fids_head["nasion"][1] > 0.01 # forward | |
| np.testing.assert_allclose(fids_head["rpa"][2:], 0, atol=1e-6) | |
| assert 0.1 > fids_head["rpa"][0] > 0.01 # to the right | |
| ini_head = -fids_head["nasion"] | |
| fids["ini"] = mne.transforms.apply_trans( | |
| mne.transforms.invert_transform(mri_head_t), ini_head | |
| ) | |
| with np.printoptions(suppress=True, floatmode="fixed"): | |
| for key, val in fids.items(): | |
| print(f"cfg.fiducial.{key[:3]} = {list(map(float, 1000 * val))};") | |
| # Run afterward: create 1020 variant | |
| path = Path(mne.channels.__file__).parent / "data" / "montages" / "fsaverage_1005.tsv" | |
| if path.is_file(): | |
| data = pd.read_csv(path, sep="\t") | |
| # Get rid of "INI" and "Nz" | |
| data = data[(data["label"] != "INI") & (data["label"] != "Nz")] | |
| want_ch_names = mne.channels.make_standard_montage("colin27_1005").ch_names | |
| # in our colin27 but not in spherical or fsaverage montages | |
| bad_names = {'A1', 'T6', 'M2', 'T4', 'T3', 'M1', 'A2', 'T5'} | |
| want_ch_names = [ch_name for ch_name in want_ch_names if ch_name not in bad_names] | |
| spherical_ch_names = mne.channels.make_standard_montage("spherical_1005").ch_names | |
| missing_from_spherical = {"NFp2", "NFp1", "NFp2h", "NFpz", "N2h", "NFp1h", "N2", "N1h", "N1"} | |
| spherical_ch_names = [ch_name for ch_name in spherical_ch_names if ch_name not in missing_from_spherical] | |
| assert set(spherical_ch_names) == set(want_ch_names) | |
| want_fids = ["NAS", "LPA", "RPA"] | |
| assert data["label"].isin(want_ch_names + list(want_fids)).all() | |
| assert len(data) == len(want_ch_names) + len(want_fids) | |
| for extra, count in (("1020", 24),): | |
| new_names = mne.channels.make_standard_montage(f"spherical_{extra}").ch_names | |
| mask = data["label"].isin(new_names + want_fids) | |
| this_data = data[mask] | |
| assert mask.sum() == count, mask.sum() | |
| spherical_ch_names = mne.channels.make_standard_montage(f"spherical_{extra}").ch_names | |
| assert set(spherical_ch_names) == set(new_names) | |
| this_data.to_csv( | |
| path.with_name(f"fsaverage_{extra}.tsv"), sep="\t", index=False | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment