Matplotlib - Simulation von Farbsehdysfunktionen

PythonPythonBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Matplotlib ist eine beliebte Datenvisualisierungsbibliothek in Python. Es hat verschiedene integrierte Funktionen, darunter die Möglichkeit, Farbsehensstörungen zu simulieren. In diesem Lab werden Sie durch die Schritte geführt, um Matplotlib zu verwenden, um Farbsehensstörungen zu simulieren.

Tipps für die VM

Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu nutzen.

Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook fertig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.

Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.

Importieren der erforderlichen Bibliotheken und Module

Zunächst müssen wir die erforderlichen Bibliotheken und Module importieren, einschließlich Matplotlib, NumPy und colorspacious. Wir legen auch die Farbfilteroptionen fest, die wir simulieren möchten.

import functools
from pathlib import Path

import colorspacious

import numpy as np

_BUTTON_NAME = "Filter"
_BUTTON_HELP = "Simulate color vision deficiencies"
_MENU_ENTRIES = {
    "None": None,
    "Greyscale": "greyscale",
    "Deuteranopia": "deuteranomaly",
    "Protanopia": "protanomaly",
    "Tritanopia": "tritanomaly",
}

Definieren der Farbfilterfunktion

Als nächstes definieren wir eine Funktion, die eine Farbfilterfunktion basierend auf dem Namen des Farbfilters erstellt. Diese Funktion verwendet das colorspacious-Modul, um das Eingabebild in einen anderen Farbraum basierend auf dem Namen des Farbfilters umzuwandeln.

def _get_color_filter(name):
    """
    Gegeben einen Namen für einen Farbfilter, erstellt eine Farbfilterfunktion.

    Parameter
    ----------
    name : str
        Der Name des Farbfilters, einer der folgenden:

        - ``"none"``:...
        - ``"greyscale"``: Konvertiert die Eingabe in Helligkeit.
        - ``"deuteranopia"``: Simuliert die häufigste Form von Rot-Grün-Farbenblindheit.
        - ``"protanopia"``: Simuliert eine seltnere Form von Rot-Grün-Farbenblindheit.
        - ``"tritanopia"``: Simuliert die seltene Form von Blau-Gelb-Farbenblindheit.

        Farbkonvertierungen verwenden `colorspacious`_.

    Rückgabe
    -------
    callable
        Eine Farbfilterfunktion der Form:

        def filter(input: np.ndarray[M, N, D])-> np.ndarray[M, N, D]

        wobei (M, N) die Bilddimensionen sind und D die Farbtiefe (3 für RGB, 4 für RGBA). Alpha wird unverändert weitergeleitet und sonst ignoriert.
    """
    if name not in _MENU_ENTRIES:
        raise ValueError(f"Unsupported filter name: {name!r}")
    name = _MENU_ENTRIES[name]

    if name is None:
        return None

    elif name == "greyscale":
        rgb_to_jch = colorspacious.cspace_converter("sRGB1", "JCh")
        jch_to_rgb = colorspacious.cspace_converter("JCh", "sRGB1")

        def convert(im):
            greyscale_JCh = rgb_to_jch(im)
            greyscale_JCh[..., 1] = 0
            im = jch_to_rgb(greyscale_JCh)
            return im

    else:
        cvd_space = {"name": "sRGB1+CVD", "cvd_type": name, "severity": 100}
        convert = colorspacious.cspace_converter(cvd_space, "sRGB1")

    def filter_func(im, dpi):
        alpha = None
        if im.shape[-1] == 4:
            im, alpha = im[..., :3], im[..., 3]
        im = convert(im)
        if alpha is not None:
            im = np.dstack((im, alpha))
        return np.clip(im, 0, 1), 0, 0

    return filter_func

Menüeintrag festlegen

Wir definieren eine Funktion, die den Menüeintrag basierend auf dem ausgewählten Namen des Farbfilters festlegt. Diese Funktion aktualisiert die Farbfilterfunktion basierend auf der Auswahl.

def _set_menu_entry(tb, name):
    tb.canvas.figure.set_agg_filter(_get_color_filter(name))
    tb.canvas.draw_idle()

Werkzeugleiste einrichten

Als nächstes definieren wir eine Funktion, die die Werkzeugleiste basierend auf dem verwendeten Backendtyp einrichtet. Diese Funktion erstellt einen Button, der dem Benutzer ermöglicht, den Typ des Farbfilters auszuwählen, den er simulieren möchte.

def setup(figure):
    tb = figure.canvas.toolbar
    if tb is None:
        return
    for cls in type(tb).__mro__:
        pkg = cls.__module__.split(".")[0]
        if pkg!= "matplotlib":
            break
    if pkg == "gi":
        _setup_gtk(tb)
    elif pkg in ("PyQt5", "PySide2", "PyQt6", "PySide6"):
        _setup_qt(tb)
    elif pkg == "tkinter":
        _setup_tk(tb)
    elif pkg == "wx":
        _setup_wx(tb)
    else:
        raise NotImplementedError("The current backend is not supported")

Beispielbilder erstellen

Wir erstellen Beispielbilder, um die Farbfilterfunktion zu demonstrieren. Wir importieren ein Beispielbild von Grace Hopper und plotten es mit Matplotlib. Wir erstellen auch einen Plot von Sinuswellen.

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    from matplotlib import cbook

    plt.rcParams['figure.hooks'].append('mplcvd:setup')

    fig, axd = plt.subplot_mosaic(
        [
            ['viridis', 'turbo'],
            ['photo', 'lines']
        ]
    )

    delta = 0.025
    x = y = np.arange(-3.0, 3.0, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = np.exp(-X**2 - Y**2)
    Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
    Z = (Z1 - Z2) * 2

    imv = axd['viridis'].imshow(
        Z, interpolation='bilinear',
        origin='lower', extent=[-3, 3, -3, 3],
        vmax=abs(Z).max(), vmin=-abs(Z).max()
    )
    fig.colorbar(imv)
    imt = axd['turbo'].imshow(
        Z, interpolation='bilinear', cmap='turbo',
        origin='lower', extent=[-3, 3, -3, 3],
        vmax=abs(Z).max(), vmin=-abs(Z).max()
    )
    fig.colorbar(imt)

    ## A sample image
    with cbook.get_sample_data('grace_hopper.jpg') as image_file:
        photo = plt.imread(image_file)
    axd['photo'].imshow(photo)

    th = np.linspace(0, 2*np.pi, 1024)
    for j in [1, 2, 4, 6]:
        axd['lines'].plot(th, np.sin(th * j), label=f'$\\omega={j}$')
    axd['lines'].legend(ncols=2, loc='upper right')
    plt.show()

Zusammenfassung

In diesem Lab haben wir gelernt, wie man mit Matplotlib Farbsehdysfunktionen simulieren kann. Wir haben das colorspacious-Modul verwendet, um das Eingabebild in einen anderen Farbraum basierend auf dem ausgewählten Namen des Farbfilters umzuwandeln. Wir haben auch Beispielbilder erstellt, um die Farbfilterfunktion zu demonstrieren.