225 lines
7.8 KiB
Python
225 lines
7.8 KiB
Python
# Authors: The MNE-Python contributors.
|
|
# License: BSD-3-Clause
|
|
# Copyright the MNE-Python contributors.
|
|
|
|
from ..utils import get_config, verbose
|
|
|
|
|
|
@verbose
|
|
def coregistration(
|
|
*,
|
|
width=None,
|
|
height=None,
|
|
inst=None,
|
|
subject=None,
|
|
subjects_dir=None,
|
|
head_opacity=None,
|
|
head_high_res=None,
|
|
trans=None,
|
|
orient_to_surface=None,
|
|
scale_by_distance=None,
|
|
mark_inside=None,
|
|
interaction=None,
|
|
fullscreen=None,
|
|
show=True,
|
|
block=False,
|
|
verbose=None,
|
|
):
|
|
"""Coregister an MRI with a subject's head shape.
|
|
|
|
The GUI can be launched through the command line interface:
|
|
|
|
.. code-block:: bash
|
|
|
|
$ mne coreg
|
|
|
|
or using a python interpreter as shown in :ref:`tut-source-alignment`.
|
|
|
|
Parameters
|
|
----------
|
|
width : int | None
|
|
Specify the width for window (in logical pixels).
|
|
Default is None, which uses ``MNE_COREG_WINDOW_WIDTH`` config value
|
|
(which defaults to 800).
|
|
height : int | None
|
|
Specify a height for window (in logical pixels).
|
|
Default is None, which uses ``MNE_COREG_WINDOW_WIDTH`` config value
|
|
(which defaults to 400).
|
|
inst : None | str
|
|
Path to an instance file containing the digitizer data. Compatible for
|
|
Raw, Epochs, and Evoked files.
|
|
subject : None | str
|
|
Name of the mri subject.
|
|
%(subjects_dir)s
|
|
head_opacity : float | None
|
|
The opacity of the head surface in the range [0., 1.].
|
|
Default is None, which uses ``MNE_COREG_HEAD_OPACITY`` config value
|
|
(which defaults to 1.).
|
|
head_high_res : bool | None
|
|
Use a high resolution head surface.
|
|
Default is None, which uses ``MNE_COREG_HEAD_HIGH_RES`` config value
|
|
(which defaults to True).
|
|
trans : path-like | None
|
|
The transform file to use.
|
|
orient_to_surface : bool | None
|
|
If True (default), orient EEG electrode and head shape points
|
|
to the head surface.
|
|
|
|
.. versionadded:: 0.16
|
|
scale_by_distance : bool | None
|
|
If True (default), scale the digitization points by their
|
|
distance from the scalp surface.
|
|
|
|
.. versionadded:: 0.16
|
|
mark_inside : bool | None
|
|
If True (default), mark points inside the head surface in a
|
|
different color.
|
|
|
|
.. versionadded:: 0.16
|
|
%(interaction_scene_none)s
|
|
Defaults to ``'terrain'``.
|
|
|
|
.. versionadded:: 0.16
|
|
.. versionchanged:: 1.0
|
|
Default interaction mode if ``None`` and no config setting found
|
|
changed from ``'trackball'`` to ``'terrain'``.
|
|
%(fullscreen)s
|
|
Default is None, which uses ``MNE_COREG_FULLSCREEN`` config value
|
|
(which defaults to False).
|
|
|
|
.. versionadded:: 1.1
|
|
show : bool
|
|
Show the GUI if True.
|
|
block : bool
|
|
Whether to halt program execution until the figure is closed.
|
|
%(verbose)s
|
|
|
|
Returns
|
|
-------
|
|
frame : instance of CoregistrationUI
|
|
The coregistration frame.
|
|
|
|
Notes
|
|
-----
|
|
Many parameters (e.g., ``head_opacity``) take None as a parameter,
|
|
which means that the default will be read from the MNE-Python
|
|
configuration file (which gets saved when exiting).
|
|
|
|
Step by step instructions for the coregistrations are shown below:
|
|
|
|
.. youtube:: ALV5qqMHLlQ
|
|
"""
|
|
config = get_config()
|
|
if head_high_res is None:
|
|
head_high_res = config.get("MNE_COREG_HEAD_HIGH_RES", "true") == "true"
|
|
if head_opacity is None:
|
|
head_opacity = config.get("MNE_COREG_HEAD_OPACITY", 0.8)
|
|
if width is None:
|
|
width = config.get("MNE_COREG_WINDOW_WIDTH", 800)
|
|
if height is None:
|
|
height = config.get("MNE_COREG_WINDOW_HEIGHT", 600)
|
|
if subjects_dir is None:
|
|
if "SUBJECTS_DIR" in config:
|
|
subjects_dir = config["SUBJECTS_DIR"]
|
|
elif "MNE_COREG_SUBJECTS_DIR" in config:
|
|
subjects_dir = config["MNE_COREG_SUBJECTS_DIR"]
|
|
false_like = ("false", "0")
|
|
if orient_to_surface is None:
|
|
orient_to_surface = config.get("MNE_COREG_ORIENT_TO_SURFACE", "true").lower()
|
|
orient_to_surface = orient_to_surface not in false_like
|
|
if scale_by_distance is None:
|
|
scale_by_distance = config.get("MNE_COREG_SCALE_BY_DISTANCE", "true").lower()
|
|
scale_by_distance = scale_by_distance not in false_like
|
|
if interaction is None:
|
|
interaction = config.get("MNE_COREG_INTERACTION", "terrain")
|
|
if mark_inside is None:
|
|
mark_inside = config.get("MNE_COREG_MARK_INSIDE", "true").lower()
|
|
mark_inside = mark_inside not in false_like
|
|
if fullscreen is None:
|
|
fullscreen = config.get("MNE_COREG_FULLSCREEN", "") == "true"
|
|
head_opacity = float(head_opacity)
|
|
width = int(width)
|
|
height = int(height)
|
|
|
|
from ..viz.backends.renderer import MNE_3D_BACKEND_TESTING
|
|
from ._coreg import CoregistrationUI
|
|
|
|
if MNE_3D_BACKEND_TESTING:
|
|
show = block = False
|
|
return CoregistrationUI(
|
|
info_file=inst,
|
|
subject=subject,
|
|
subjects_dir=subjects_dir,
|
|
head_resolution=head_high_res,
|
|
head_opacity=head_opacity,
|
|
orient_glyphs=orient_to_surface,
|
|
scale_by_distance=scale_by_distance,
|
|
mark_inside=mark_inside,
|
|
trans=trans,
|
|
size=(width, height),
|
|
show=show,
|
|
block=block,
|
|
interaction=interaction,
|
|
fullscreen=fullscreen,
|
|
verbose=verbose,
|
|
)
|
|
|
|
|
|
class _GUIScraper:
|
|
"""Scrape GUI outputs."""
|
|
|
|
def __repr__(self):
|
|
return "<GUIScraper>"
|
|
|
|
def __call__(self, block, block_vars, gallery_conf):
|
|
from ._coreg import CoregistrationUI
|
|
|
|
gui_classes = (CoregistrationUI,)
|
|
try:
|
|
from mne_gui_addons._ieeg_locate import (
|
|
IntracranialElectrodeLocator,
|
|
)
|
|
except Exception:
|
|
pass
|
|
else:
|
|
gui_classes = gui_classes + (IntracranialElectrodeLocator,)
|
|
from qtpy import QtGui
|
|
from sphinx_gallery.scrapers import figure_rst
|
|
|
|
for gui in block_vars["example_globals"].values():
|
|
if (
|
|
isinstance(gui, gui_classes)
|
|
and not getattr(gui, "_scraped", False)
|
|
and gallery_conf["builder_name"] == "html"
|
|
):
|
|
gui._scraped = True # monkey-patch but it's easy enough
|
|
img_fname = next(block_vars["image_path_iterator"])
|
|
# TODO fix in window refactor
|
|
window = gui if hasattr(gui, "grab") else gui._renderer._window
|
|
# window is QWindow
|
|
# https://doc.qt.io/qt-5/qwidget.html#grab
|
|
pixmap = window.grab()
|
|
if hasattr(gui, "_renderer"): # if no renderer, no need
|
|
# Now the tricky part: we need to get the 3D renderer,
|
|
# extract the image from it, and put it in the correct
|
|
# place in the pixmap. The easiest way to do this is
|
|
# actually to save the 3D image first, then load it
|
|
# using QPixmap and Qt geometry.
|
|
plotter = gui._renderer.plotter
|
|
plotter.screenshot(img_fname)
|
|
sub_pixmap = QtGui.QPixmap(img_fname)
|
|
# https://doc.qt.io/qt-5/qwidget.html#mapTo
|
|
# https://doc.qt.io/qt-5/qpainter.html#drawPixmap-1
|
|
QtGui.QPainter(pixmap).drawPixmap(
|
|
plotter.mapTo(window, plotter.rect().topLeft()), sub_pixmap
|
|
)
|
|
# https://doc.qt.io/qt-5/qpixmap.html#save
|
|
pixmap.save(img_fname)
|
|
try: # for compatibility with both GUIs, will be refactored
|
|
gui._renderer.close() # TODO should be triggered by close
|
|
except Exception:
|
|
pass
|
|
gui.close()
|
|
return figure_rst([img_fname], gallery_conf["src_dir"], "GUI")
|
|
return ""
|