# 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 "" 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 ""