注意
转到末尾以下载完整的示例代码。
图像教程#
一个关于使用 Matplotlib 绘制图像的简短教程。
启动命令#
首先,让我们启动 IPython。它是对标准 Python 提示符的一个非常好的增强,并且与 Matplotlib 结合得特别好。直接在 shell 中或使用 Jupyter Notebook(其中 IPython 作为运行内核)启动 IPython。
启动 IPython 后,我们需要连接到一个 GUI 事件循环。这告诉 IPython 在哪里(以及如何)显示绘图。要连接到 GUI 循环,请在 IPython 提示符下执行 %matplotlib magic 命令。有关此命令具体作用的更多详细信息,请参阅 IPython 关于 GUI 事件循环的文档。
如果您正在使用 Jupyter Notebook,则可以使用相同的命令,但人们通常对 %matplotlib magic 使用特定的参数
In [1]: %matplotlib inline
这将启用内联绘图,其中绘图图形将显示在您的 notebook 中。这对交互性有重要影响。对于内联绘图,在输出绘图的单元格下方的单元格中的命令将不会影响绘图。例如,无法从创建绘图的单元格下方的单元格更改颜色图。但是,对于其他后端(例如 Qt),它们会打开单独的窗口,创建绘图的单元格下方的单元格将更改绘图 - 它是内存中的活动对象。
本教程将使用 Matplotlib 的隐式绘图界面 pyplot。此界面维护全局状态,对于快速轻松地试验各种绘图设置非常有用。另一种选择是显式界面,它更适合大型应用程序开发。有关隐式和显式界面之间权衡的解释,请参阅Matplotlib 应用程序接口 (API)和快速入门指南,开始使用显式界面。现在,让我们继续使用隐式方法
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
将图像数据导入 Numpy 数组#
Matplotlib 依赖于 Pillow 库来加载图像数据。
这是我们要使用的图像
它是一个 24 位 RGB PNG 图像(R、G、B 各 8 位)。根据您获取数据的位置,您最可能遇到的其他图像类型是 RGBA 图像(允许透明度)或单通道灰度(亮度)图像。下载 stinkbug.png 到您的计算机,以便在本教程的其余部分中使用。
我们使用 Pillow 打开图像(使用 PIL.Image.open
),并立即将 PIL.Image.Image
对象转换为 8 位 (dtype=uint8
) numpy 数组。
img = np.asarray(Image.open('../../doc/_static/stinkbug.png'))
print(repr(img))
array([[[104, 104, 104],
[104, 104, 104],
[104, 104, 104],
...,
[109, 109, 109],
[109, 109, 109],
[109, 109, 109]],
[[105, 105, 105],
[105, 105, 105],
[105, 105, 105],
...,
[109, 109, 109],
[109, 109, 109],
[109, 109, 109]],
[[107, 107, 107],
[106, 106, 106],
[106, 106, 106],
...,
[110, 110, 110],
[110, 110, 110],
[110, 110, 110]],
...,
[[112, 112, 112],
[111, 111, 111],
[110, 110, 110],
...,
[116, 116, 116],
[115, 115, 115],
[115, 115, 115]],
[[113, 113, 113],
[113, 113, 113],
[112, 112, 112],
...,
[115, 115, 115],
[114, 114, 114],
[114, 114, 114]],
[[113, 113, 113],
[115, 115, 115],
[115, 115, 115],
...,
[114, 114, 114],
[114, 114, 114],
[113, 113, 113]]], dtype=uint8)
每个内部列表代表一个像素。在这里,对于 RGB 图像,有 3 个值。由于它是黑白图像,因此 R、G 和 B 都相似。RGBA(其中 A 是 alpha 或透明度)每个内部列表有 4 个值,而简单的亮度图像只有一个值(因此只是 2 维数组,而不是 3 维数组)。对于 RGB 和 RGBA 图像,Matplotlib 支持 float32 和 uint8 数据类型。对于灰度图像,Matplotlib 仅支持 float32。如果您的数组数据不符合这些描述中的任何一种,则需要重新缩放它。
将 numpy 数组绘制为图像#
因此,您的数据在 numpy 数组中(通过导入或生成)。让我们渲染它。在 Matplotlib 中,这是使用 imshow()
函数执行的。在这里,我们将获取绘图对象。此对象使您可以轻松地从提示符操作绘图。
imgplot = plt.imshow(img)
您还可以绘制任何 numpy 数组。
将伪彩色方案应用于图像绘图#
伪彩色可以成为增强对比度和更轻松地可视化数据的有用工具。当使用投影仪演示数据时,这尤其有用 - 它们的对比度通常很差。
伪彩色仅与单通道、灰度、亮度图像相关。我们目前有一个 RGB 图像。由于 R、G 和 B 都相似(请亲自查看上方或在您的数据中),我们可以使用数组切片仅选取我们数据的一个通道(您可以在 Numpy 教程中阅读更多内容)
lum_img = img[:, :, 0]
plt.imshow(lum_img)
现在,对于亮度(2D,无颜色)图像,应用默认颜色图(也称为查找表,LUT)。默认值称为 viridis。还有很多其他的可供选择。
plt.imshow(lum_img, cmap="hot")
请注意,您还可以使用 set_cmap()
方法更改现有绘图对象上的颜色图
imgplot = plt.imshow(lum_img)
imgplot.set_cmap('nipy_spectral')
注意
但是,请记住,在具有内联后端的 Jupyter Notebook 中,您无法对已渲染的绘图进行更改。如果您在一个单元格中创建了 imgplot,则无法在后面的单元格中对其调用 set_cmap() 并期望先前的绘图发生更改。请确保您在同一个单元格中一起输入这些命令。plt 命令不会更改先前单元格中的绘图。
还有许多其他可用的颜色图方案。请参阅颜色图的列表和图像。
颜色刻度参考#
了解颜色代表什么值很有帮助。我们可以通过向您的图中添加颜色条来实现
检查特定的数据范围#
有时您想增强图像的对比度,或扩大特定区域的对比度,同时牺牲颜色变化不大或不重要的细节。查找有趣区域的一个好工具是直方图。要创建我们图像数据的直方图,我们使用 hist()
函数。
大多数情况下,图像的“有趣”部分在峰值附近,您可以通过裁剪峰值上方和/或下方的区域来获得额外的对比度。在我们的直方图中,看起来高端没有太多有用的信息(图像中没有太多白色物体)。让我们调整上限,以便我们有效地“放大”直方图的一部分。我们通过设置 clim(颜色图限制)来做到这一点。
这可以通过在调用 imshow
时传递 clim 关键字参数来完成。
plt.imshow(lum_img, clim=(0, 175))
这也可以通过调用返回的图像绘图对象的 set_clim()
方法来完成,但请确保在与 Jupyter Notebook 一起使用时,在与绘图命令相同的单元格中执行此操作 - 它不会更改先前单元格中的绘图。
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0, 175)
数组插值方案#
插值根据不同的数学方案计算像素的颜色或值“应该”是什么。发生这种情况的一个常见位置是在调整图像大小时。像素数量会发生变化,但您需要相同的信息。由于像素是离散的,因此缺少空间。插值是您如何填充该空间。这就是为什么当您放大图像时,您的图像有时会出现像素化。当原始图像和放大图像之间的差异较大时,效果会更明显。让我们获取我们的图像并缩小它。我们正在有效地丢弃像素,只保留少数几个。现在,当我们绘制它时,该数据会被放大到屏幕上的大小。旧的像素不再存在,计算机必须绘制像素来填充该空间。
我们将使用我们用来加载图像的 Pillow 库来调整图像大小。
img = Image.open('../../doc/_static/stinkbug.png')
img.thumbnail((64, 64)) # resizes image in-place
imgplot = plt.imshow(img)
在这里,我们使用默认插值(“最近邻”),因为我们没有为 imshow()
提供任何插值参数。
让我们尝试一些其他的。这是“双线性”
imgplot = plt.imshow(img, interpolation="bilinear")
和双三次
imgplot = plt.imshow(img, interpolation="bicubic")
双三次插值通常在放大照片时使用 - 人们倾向于喜欢模糊而不是像素化。
脚本总运行时间: (0 分钟 9.582 秒)