简介
Matplotlib 是 Python 中一个流行的数据可视化库。它有各种内置功能,包括模拟色觉缺陷的能力。本实验将指导你完成使用 Matplotlib 模拟色觉缺陷的步骤。
虚拟机使用提示
虚拟机启动完成后,点击左上角切换到“笔记本”标签页,以访问 Jupyter Notebook 进行练习。
有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。
如果你在学习过程中遇到问题,随时向 Labby 提问。课程结束后提供反馈,我们会及时为你解决问题。
导入必要的库和模块
首先,我们需要导入必要的库和模块,包括 Matplotlib、NumPy 和 colorspacious。我们还设置了想要模拟的颜色滤镜选项。
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",
}
定义颜色滤镜函数
接下来,我们定义一个函数,该函数根据颜色滤镜名称创建一个颜色滤镜函数。此函数使用 colorspacious 模块根据颜色滤镜名称将输入图像转换为不同的颜色空间。
def _get_color_filter(name):
"""
给定一个颜色滤镜名称,创建一个颜色滤镜函数。
参数
----------
name : str
颜色滤镜名称,以下之一:
- ``"none"``:...
- ``"greyscale"``: 将输入转换为亮度。
- ``"deuteranopia"``: 模拟最常见的红绿色盲形式。
- ``"protanopia"``: 模拟一种较罕见的红绿色盲形式。
- ``"tritanopia"``: 模拟罕见的蓝黄色盲形式。
颜色转换使用 `colorspacious`_。
返回
-------
callable
一个颜色滤镜函数,其形式为:
def filter(input: np.ndarray[M, N, D])-> np.ndarray[M, N, D]
其中 (M, N) 是图像尺寸,D 是颜色深度(RGB 为 3,RGBA 为 4)。透明度通道直接传递,其他情况下忽略。
"""
if name not in _MENU_ENTRIES:
raise ValueError(f"不支持的滤镜名称:{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
设置菜单项
我们定义一个函数,该函数根据所选的颜色滤镜名称设置菜单项。此函数会根据所选内容更新颜色滤镜函数。
def _set_menu_entry(tb, name):
tb.canvas.figure.set_agg_filter(_get_color_filter(name))
tb.canvas.draw_idle()
设置工具栏
接下来,我们定义一个函数,该函数根据所使用的后端类型来设置工具栏。此函数创建一个按钮,允许用户选择要模拟的颜色滤镜类型。
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")
创建示例图像
我们创建示例图像以演示颜色滤镜功能。我们导入一张格蕾丝·霍珀(Grace Hopper)的示例图像,并使用 Matplotlib 进行绘制。我们还创建了一个正弦波的图表。
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)
## 一张示例图像
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()
总结
在本实验中,我们学习了如何使用 Matplotlib 模拟色觉缺陷。我们使用 colorspacious 模块根据所选的颜色滤镜名称将输入图像转换为不同的颜色空间。我们还创建了示例图像来演示颜色滤镜功能。