图像抗锯齿#

图像由屏幕或图像文件上的离散像素表示。当构成图像的数据的分辨率与屏幕上的表示不同时,我们会看到混叠现象。这些现象的明显程度取决于分辨率变化过程中(如果有)下采样的程度。

在对数据进行下采样时,通过先平滑,然后对平滑后的数据进行下采样,可以减少混叠现象。在 Matplotlib 中,我们可以先对数据进行平滑,然后再将其映射到颜色,或者在最终图像的 RGB(A) 数据上进行平滑处理。这些方法之间的差异显示如下,并由 interpolation_stage 关键字参数控制。

Matplotlib 中的默认图像插值是 'antialiased',它应用于数据。这在用户提供的数据上使用汉宁插值,以在大多数情况下减少混叠。只有当上采样因子为 1、2 或 >=3 时,才会使用 'nearest' 邻近插值。

可以在 Axes.imshow 中使用 interpolation 关键字参数指定其他抗锯齿滤镜。

import matplotlib.pyplot as plt
import numpy as np

首先,我们生成一个 450x450 像素的图像,其频率内容不同

N = 450
x = np.arange(N) / N - 0.5
y = np.arange(N) / N - 0.5
aa = np.ones((N, N))
aa[::2, :] = -1

X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
f0 = 5
k = 100
a = np.sin(np.pi * 2 * (f0 * R + k * R**2 / 2))
# make the left hand side of this
a[:int(N / 2), :][R[:int(N / 2), :] < 0.4] = -1
a[:int(N / 2), :][R[:int(N / 2), :] < 0.3] = 1
aa[:, int(N / 3):] = a[:, int(N / 3):]
a = aa

以下图像从 450 个数据像素下采样到 125 像素或 250 像素(取决于您的显示器)。'nearest' 插值中的莫尔条纹是由高频数据被下采样引起的。'antialiased' 图像也有一些莫尔条纹,但它们被大大减少了。

'data' 插值和 'rgba' 插值之间存在很大差异。图像左侧三分之一的红色和蓝色交替条带被下采样。通过在 'data' 空间(默认值)中进行插值,抗锯齿滤镜使条纹接近白色,因为 -1 和 +1 的平均值为零,而零在这个颜色图中是白色。

相反,当抗锯齿在 'rgba' 空间中发生时,红色和蓝色在视觉上组合在一起形成紫色。这种行为更像是一个典型的图像处理软件包,但请注意,紫色不在原始颜色图中,因此无法再将单个像素反转回其数据值。

fig, axs = plt.subplots(2, 2, figsize=(5, 6), layout='constrained')
axs[0, 0].imshow(a, interpolation='nearest', cmap='RdBu_r')
axs[0, 0].set_xlim(100, 200)
axs[0, 0].set_ylim(275, 175)
axs[0, 0].set_title('Zoom')

for ax, interp, space in zip(axs.flat[1:],
                             ['nearest', 'antialiased', 'antialiased'],
                             ['data', 'data', 'rgba']):
    ax.imshow(a, interpolation=interp, interpolation_stage=space,
              cmap='RdBu_r')
    ax.set_title(f"interpolation='{interp}'\nspace='{space}'")
plt.show()
Zoom, interpolation='nearest' space='data', interpolation='antialiased' space='data', interpolation='antialiased' space='rgba'

即使使用 'nearest' 插值对图像进行上采样,当上采样因子不是整数时,也会导致莫尔条纹。以下图像将 500 个数据像素上采样到 530 个渲染像素。您可能会注意到 30 条线状伪影的网格,这些伪影源于必须弥补的 524 - 500 = 24 个额外像素。由于插值是 'nearest',因此它们与相邻像素行相同,因此会局部拉伸图像,使其看起来扭曲。

fig, ax = plt.subplots(figsize=(6.8, 6.8))
ax.imshow(a, interpolation='nearest', cmap='gray')
ax.set_title("upsampled by factor a 1.048, interpolation='nearest'")
plt.show()
upsampled by factor a 1.048, interpolation='nearest'

更好的抗锯齿算法可以减少这种影响

fig, ax = plt.subplots(figsize=(6.8, 6.8))
ax.imshow(a, interpolation='antialiased', cmap='gray')
ax.set_title("upsampled by factor a 1.048, interpolation='antialiased'")
plt.show()
upsampled by factor a 1.048, interpolation='antialiased'

除了默认的 'hanning' 抗锯齿之外,imshow 支持多种不同的插值算法,这些算法在不同模式下可能效果更好或更差。

fig, axs = plt.subplots(1, 2, figsize=(7, 4), layout='constrained')
for ax, interp in zip(axs, ['hanning', 'lanczos']):
    ax.imshow(a, interpolation=interp, cmap='gray')
    ax.set_title(f"interpolation='{interp}'")
plt.show()
interpolation='hanning', interpolation='lanczos'

参考文献

本示例中演示了以下函数、方法、类和模块的使用

脚本的总运行时间:(0 分钟 3.532 秒)

由 Sphinx-Gallery 生成的图库