Simulation de déficiences de la vision colorée avec Matplotlib

Beginner

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

Introduction

Matplotlib est une bibliothèque populaire de visualisation de données en Python. Elle dispose de diverses fonctionnalités intégrées, notamment la capacité de simuler des déficiences de la vision colorée. Ce laboratoire vous guidera tout au long des étapes d'utilisation de Matplotlib pour simuler des déficiences de la vision colorée.

Conseils sur la machine virtuelle

Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Carnet d'étude pour accéder au carnet Jupyter pour pratiquer.

Parfois, vous devrez peut-être attendre quelques secondes pour que le carnet Jupyter ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations du carnet Jupyter.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.

Importez les bibliothèques et les modules nécessaires

Tout d'abord, nous devons importer les bibliothèques et les modules nécessaires, notamment Matplotlib, NumPy et colorspacious. Nous définissons également les options de filtre de couleur que nous souhaitons simuler.

import functools
from pathlib import Path

import colorspacious

import numpy as np

_BUTTON_NAME = "Filter"
_BUTTON_HELP = "Simuler les déficiences de la vision colorée"
_MENU_ENTRIES = {
    "None": None,
    "Greyscale": "greyscale",
    "Deuteranopia": "deuteranomaly",
    "Protanopia": "protanomaly",
    "Tritanopia": "tritanomaly",
}

Définissez la fonction de filtre de couleur

Ensuite, nous définissons une fonction qui crée une fonction de filtre de couleur en fonction du nom du filtre de couleur. Cette fonction utilise le module colorspacious pour convertir l'image d'entrée dans un espace de couleur différent en fonction du nom du filtre de couleur.

def _get_color_filter(name):
    """
    Étant donné un nom de filtre de couleur, crée une fonction de filtre de couleur.

    Paramètres
    ----------
    name : str
        Le nom du filtre de couleur, l'un des suivants :

        - ``"none"``:...
        - ``"greyscale"``: Convertissez l'entrée en luminosité.
        - ``"deuteranopia"``: Simulez la forme la plus courante de daltonisme rouge-vert.
        - ``"protanopia"``: Simulez une forme plus rare de daltonisme rouge-vert.
        - ``"tritanopia"``: Simulez la forme rare de daltonisme bleu-jaune.

        Les conversions de couleur utilisent `colorspacious`_.

    Retours
    -------
    callable
        Une fonction de filtre de couleur qui a la forme :

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

        où (M, N) sont les dimensions de l'image et D est la profondeur de couleur (3 pour RGB, 4 pour RGBA). L'alpha est transmis tel quel et sinon ignoré.
    """
    if name not in _MENU_ENTRIES:
        raise ValueError(f"Nom de filtre non pris en charge : {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

Définissez l'entrée du menu

Nous définissons une fonction qui définit l'entrée du menu en fonction du nom du filtre de couleur sélectionné. Cette fonction met à jour la fonction de filtre de couleur en fonction de la sélection.

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

Configurez la barre d'outils

Ensuite, nous définissons une fonction qui configure la barre d'outils en fonction du type de backend utilisé. Cette fonction crée un bouton qui permet à l'utilisateur de sélectionner le type de filtre de couleur à simuler.

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("Le backend actuel n'est pas pris en charge")

Créez des images d'échantillonnage

Nous créons des images d'échantillonnage pour démontrer la fonction de filtre de couleur. Nous importons une image d'échantillonnage de Grace Hopper et la traçons à l'aide de Matplotlib. Nous créons également un tracé d'ondes sinusoïdales.

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)

    ## Une image d'échantillonnage
    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()

Sommaire

Dans ce laboratoire, nous avons appris à simuler les déficiences de la vision colorée à l'aide de Matplotlib. Nous avons utilisé le module colorspacious pour convertir l'image d'entrée dans un espace de couleur différent en fonction du nom du filtre de couleur sélectionné. Nous avons également créé des images d'échantillonnage pour démontrer la fonction de filtre de couleur.