笔记
单击此处 下载完整的示例代码
图片教程#
使用 Matplotlib 绘制图像的简短教程。
启动命令#
首先,让我们启动 IPython。它是对标准 Python 提示的最出色的增强,它与 Matplotlib 结合得特别好。直接在 shell 或 Jupyter Notebook(其中 IPython 作为运行内核)启动 IPython。
随着 IPython 的启动,我们现在需要连接到一个 GUI 事件循环。这告诉 IPython 在哪里(以及如何)显示绘图。要连接到 GUI 循环,请在 IPython 提示符下执行%matplotlib魔术。在IPython 的关于 GUI 事件循环的文档中有更多详细信息。
如果您使用的是 Jupyter Notebook,则可以使用相同的命令,但人们通常使用 %matplotlib 魔术的特定参数:
In [1]: %matplotlib inline
这将打开内联绘图,绘图图形将出现在您的笔记本中。这对交互性具有重要意义。对于内联绘图,输出绘图的单元格下方的单元格中的命令不会影响绘图。例如,无法从创建绘图的单元格下方的单元格更改颜色图。但是,对于打开单独窗口的其他后端,例如 Qt,创建绘图的单元下方的单元格将更改绘图 - 它是内存中的活动对象。
本教程将使用 Matplotlib 的隐式绘图接口 pyplot。此界面维护全局状态,对于快速轻松地尝试各种绘图设置非常有用。另一种选择是显式的,它更适合大型应用程序开发。有关隐式接口和显式接口之间权衡的说明,请参阅 Matplotlib 应用程序接口 (API)和快速入门指南以开始使用显式接口。现在,让我们继续使用隐式方法:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
将图像数据导入 Numpy数组
Matplotlib 依赖Pillow库来加载图像数据。
这是我们要玩的图像:
这是一个 24 位 RGB PNG 图像(R、G、B 各 8 位)。根据您获取数据的位置,您最有可能遇到的其他类型的图像是 RGBA 图像,它允许透明度,或单通道灰度(亮度)图像。将stinkbug.png下载 到您的计算机上以完成本教程的其余部分。
现在我们开始...
img = mpimg.imread('../../doc/_static/stinkbug.png')
print(img)
[[[0.40784314 0.40784314 0.40784314]
[0.40784314 0.40784314 0.40784314]
[0.40784314 0.40784314 0.40784314]
...
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]]
[[0.4117647 0.4117647 0.4117647 ]
[0.4117647 0.4117647 0.4117647 ]
[0.4117647 0.4117647 0.4117647 ]
...
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]]
[[0.41960785 0.41960785 0.41960785]
[0.41568628 0.41568628 0.41568628]
[0.41568628 0.41568628 0.41568628]
...
[0.43137255 0.43137255 0.43137255]
[0.43137255 0.43137255 0.43137255]
[0.43137255 0.43137255 0.43137255]]
...
[[0.4392157 0.4392157 0.4392157 ]
[0.43529412 0.43529412 0.43529412]
[0.43137255 0.43137255 0.43137255]
...
[0.45490196 0.45490196 0.45490196]
[0.4509804 0.4509804 0.4509804 ]
[0.4509804 0.4509804 0.4509804 ]]
[[0.44313726 0.44313726 0.44313726]
[0.44313726 0.44313726 0.44313726]
[0.4392157 0.4392157 0.4392157 ]
...
[0.4509804 0.4509804 0.4509804 ]
[0.44705883 0.44705883 0.44705883]
[0.44705883 0.44705883 0.44705883]]
[[0.44313726 0.44313726 0.44313726]
[0.4509804 0.4509804 0.4509804 ]
[0.4509804 0.4509804 0.4509804 ]
...
[0.44705883 0.44705883 0.44705883]
[0.44705883 0.44705883 0.44705883]
[0.44313726 0.44313726 0.44313726]]]
注意那里的dtype - float32。Matplotlib 已将每个通道的 8 位数据重新缩放为 0.0 到 1.0 之间的浮点数据。附带说明一下,Pillow 可以使用的唯一数据类型是 uint8。Matplotlib 绘图可以处理 float32 和 uint8,但除 PNG 以外的任何格式的图像读取/写入仅限于 uint8 数据。为什么是 8 位?大多数显示器每通道只能渲染 8 位的颜色渐变。为什么他们只能渲染 8 位/通道?因为那是人眼所能看到的一切。更多信息(从摄影的角度来看):Luminous Landscape 位深度教程。
每个内部列表代表一个像素。在这里,对于 RGB 图像,有 3 个值。由于它是黑白图像,因此 R、G 和 B 都相似。一个 RGBA(其中 A 是 alpha 或透明度),每个内部列表有 4 个值,而简单的亮度图像只有一个值(因此只是一个 2-D 数组,而不是 3-D 数组)。对于 RGB 和 RGBA 图像,Matplotlib 支持 float32 和 uint8 数据类型。对于灰度,Matplotlib 仅支持 float32。如果您的数组数据不符合这些描述之一,您需要重新调整它。
将 numpy 数组绘制为图像#
因此,您将数据保存在一个 numpy 数组中(通过导入或生成)。让我们渲染它。在 Matplotlib 中,这是使用imshow()
函数执行的。在这里,我们将抓取绘图对象。此对象为您提供了一种从提示操作绘图的简单方法。
imgplot = plt.imshow(img)
您还可以绘制任何 numpy 数组。
将伪彩色方案应用于图像图#
Pseudocolor 可以成为增强对比度和更轻松地可视化数据的有用工具。这在使用投影仪演示数据时特别有用——它们的对比度通常很差。
伪彩色仅与单通道、灰度、亮度图像相关。我们目前有一个 RGB 图像。由于 R、G 和 B 都是相似的(请参阅上面或数据中的内容),我们可以只选择一个数据通道:
lum_img = img[:, :, 0]
# This is array slicing. You can read more in the `Numpy tutorial
# <https://numpy.org/doc/stable/user/quickstart.html>`_.
plt.imshow(lum_img)
<matplotlib.image.AxesImage object at 0x7f2cdd608610>
现在,使用亮度(2D,无颜色)图像,应用默认颜色图(又名查找表,LUT)。默认称为 viridis。还有很多其他可供选择。
plt.imshow(lum_img, cmap="hot")
<matplotlib.image.AxesImage object at 0x7f2cddcc2aa0>
请注意,您还可以使用以下
set_cmap()
方法更改现有绘图对象的颜色图:
imgplot = plt.imshow(lum_img)
imgplot.set_cmap('nipy_spectral')
笔记
但是,请记住,在带有内联后端的 Jupyter Notebook 中,您不能对已渲染的绘图进行更改。如果您在一个单元格中创建 imgplot,则不能在稍后的单元格中对其调用 set_cmap() 并期望较早的绘图会发生变化。确保在一个单元格中同时输入这些命令。plt 命令不会更改早期单元格的绘图。
还有许多其他可用的颜色图方案。请参阅颜色图的列表和图像。
色阶参考#
了解颜色代表的价值是有帮助的。我们可以通过为您的图形添加一个颜色条来做到这一点:
<matplotlib.colorbar.Colorbar object at 0x7f2cdf5297e0>
检查特定数据范围#
有时,您希望增强图像的对比度,或扩大特定区域的对比度,同时牺牲变化不大或无关紧要的颜色细节。寻找有趣区域的一个好工具是直方图。为了创建图像数据的直方图,我们使用该hist()
函数。
(array([2.000e+00, 2.000e+00, 3.000e+00, 3.000e+00, 2.000e+00, 2.000e+00,
3.000e+00, 1.000e+00, 7.000e+00, 9.000e+00, 7.000e+00, 2.000e+00,
7.000e+00, 1.000e+01, 1.100e+01, 1.500e+01, 1.400e+01, 2.700e+01,
2.100e+01, 2.400e+01, 1.400e+01, 3.100e+01, 2.900e+01, 2.800e+01,
2.400e+01, 2.400e+01, 4.000e+01, 2.600e+01, 5.200e+01, 3.900e+01,
5.700e+01, 4.600e+01, 8.400e+01, 7.600e+01, 8.900e+01, 8.000e+01,
1.060e+02, 1.130e+02, 1.120e+02, 9.000e+01, 1.160e+02, 1.090e+02,
1.270e+02, 1.350e+02, 9.800e+01, 1.310e+02, 1.230e+02, 1.110e+02,
1.230e+02, 1.160e+02, 1.010e+02, 1.170e+02, 1.000e+02, 1.010e+02,
9.000e+01, 1.060e+02, 1.260e+02, 1.040e+02, 1.070e+02, 1.110e+02,
1.380e+02, 1.000e+02, 1.340e+02, 1.210e+02, 1.400e+02, 1.320e+02,
1.390e+02, 1.160e+02, 1.330e+02, 1.180e+02, 1.080e+02, 1.170e+02,
1.280e+02, 1.200e+02, 1.210e+02, 1.100e+02, 1.160e+02, 1.180e+02,
9.700e+01, 9.700e+01, 1.140e+02, 1.070e+02, 1.170e+02, 8.700e+01,
1.070e+02, 9.800e+01, 1.040e+02, 1.120e+02, 1.110e+02, 1.180e+02,
1.240e+02, 1.340e+02, 1.200e+02, 1.410e+02, 1.520e+02, 1.360e+02,
1.610e+02, 1.380e+02, 1.620e+02, 1.570e+02, 1.350e+02, 1.470e+02,
1.690e+02, 1.710e+02, 1.820e+02, 1.980e+02, 1.970e+02, 2.060e+02,
2.160e+02, 2.460e+02, 2.210e+02, 2.520e+02, 2.890e+02, 3.450e+02,
3.620e+02, 3.760e+02, 4.480e+02, 4.630e+02, 5.170e+02, 6.000e+02,
6.200e+02, 6.410e+02, 7.440e+02, 7.120e+02, 8.330e+02, 9.290e+02,
1.061e+03, 1.280e+03, 1.340e+03, 1.638e+03, 1.740e+03, 1.953e+03,
2.151e+03, 2.290e+03, 2.440e+03, 2.758e+03, 2.896e+03, 3.384e+03,
4.332e+03, 5.584e+03, 6.197e+03, 6.422e+03, 6.404e+03, 7.181e+03,
8.196e+03, 7.968e+03, 7.474e+03, 7.926e+03, 8.460e+03, 8.091e+03,
9.148e+03, 8.563e+03, 6.747e+03, 6.074e+03, 6.328e+03, 5.291e+03,
6.472e+03, 6.268e+03, 2.864e+03, 3.760e+02, 1.620e+02, 1.180e+02,
1.270e+02, 9.500e+01, 7.600e+01, 8.200e+01, 6.200e+01, 6.700e+01,
5.600e+01, 5.900e+01, 4.000e+01, 4.200e+01, 3.000e+01, 3.400e+01,
3.200e+01, 4.300e+01, 4.200e+01, 2.300e+01, 2.800e+01, 1.900e+01,
2.200e+01, 1.600e+01, 1.200e+01, 1.800e+01, 9.000e+00, 1.000e+01,
1.700e+01, 5.000e+00, 2.100e+01, 1.300e+01, 8.000e+00, 1.200e+01,
1.000e+01, 8.000e+00, 8.000e+00, 5.000e+00, 1.300e+01, 6.000e+00,
3.000e+00, 7.000e+00, 6.000e+00, 2.000e+00, 1.000e+00, 5.000e+00,
3.000e+00, 3.000e+00, 1.000e+00, 1.000e+00, 1.000e+00, 5.000e+00,
0.000e+00, 1.000e+00, 3.000e+00, 0.000e+00, 1.000e+00, 1.000e+00,
2.000e+00, 1.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00,
0.000e+00, 0.000e+00, 0.000e+00, 0.000e+00]), array([0. , 0.00390625, 0.0078125 , 0.01171875, 0.015625 ,
0.01953125, 0.0234375 , 0.02734375, 0.03125 , 0.03515625,
0.0390625 , 0.04296875, 0.046875 , 0.05078125, 0.0546875 ,
0.05859375, 0.0625 , 0.06640625, 0.0703125 , 0.07421875,
0.078125 , 0.08203125, 0.0859375 , 0.08984375, 0.09375 ,
0.09765625, 0.1015625 , 0.10546875, 0.109375 , 0.11328125,
0.1171875 , 0.12109375, 0.125 , 0.12890625, 0.1328125 ,
0.13671875, 0.140625 , 0.14453125, 0.1484375 , 0.15234375,
0.15625 , 0.16015625, 0.1640625 , 0.16796875, 0.171875 ,
0.17578125, 0.1796875 , 0.18359375, 0.1875 , 0.19140625,
0.1953125 , 0.19921875, 0.203125 , 0.20703125, 0.2109375 ,
0.21484375, 0.21875 , 0.22265625, 0.2265625 , 0.23046875,
0.234375 , 0.23828125, 0.2421875 , 0.24609375, 0.25 ,
0.25390625, 0.2578125 , 0.26171875, 0.265625 , 0.26953125,
0.2734375 , 0.27734375, 0.28125 , 0.28515625, 0.2890625 ,
0.29296875, 0.296875 , 0.30078125, 0.3046875 , 0.30859375,
0.3125 , 0.31640625, 0.3203125 , 0.32421875, 0.328125 ,
0.33203125, 0.3359375 , 0.33984375, 0.34375 , 0.34765625,
0.3515625 , 0.35546875, 0.359375 , 0.36328125, 0.3671875 ,
0.37109375, 0.375 , 0.37890625, 0.3828125 , 0.38671875,
0.390625 , 0.39453125, 0.3984375 , 0.40234375, 0.40625 ,
0.41015625, 0.4140625 , 0.41796875, 0.421875 , 0.42578125,
0.4296875 , 0.43359375, 0.4375 , 0.44140625, 0.4453125 ,
0.44921875, 0.453125 , 0.45703125, 0.4609375 , 0.46484375,
0.46875 , 0.47265625, 0.4765625 , 0.48046875, 0.484375 ,
0.48828125, 0.4921875 , 0.49609375, 0.5 , 0.50390625,
0.5078125 , 0.51171875, 0.515625 , 0.51953125, 0.5234375 ,
0.52734375, 0.53125 , 0.53515625, 0.5390625 , 0.54296875,
0.546875 , 0.55078125, 0.5546875 , 0.55859375, 0.5625 ,
0.56640625, 0.5703125 , 0.57421875, 0.578125 , 0.58203125,
0.5859375 , 0.58984375, 0.59375 , 0.59765625, 0.6015625 ,
0.60546875, 0.609375 , 0.61328125, 0.6171875 , 0.62109375,
0.625 , 0.62890625, 0.6328125 , 0.63671875, 0.640625 ,
0.64453125, 0.6484375 , 0.65234375, 0.65625 , 0.66015625,
0.6640625 , 0.66796875, 0.671875 , 0.67578125, 0.6796875 ,
0.68359375, 0.6875 , 0.69140625, 0.6953125 , 0.69921875,
0.703125 , 0.70703125, 0.7109375 , 0.71484375, 0.71875 ,
0.72265625, 0.7265625 , 0.73046875, 0.734375 , 0.73828125,
0.7421875 , 0.74609375, 0.75 , 0.75390625, 0.7578125 ,
0.76171875, 0.765625 , 0.76953125, 0.7734375 , 0.77734375,
0.78125 , 0.78515625, 0.7890625 , 0.79296875, 0.796875 ,
0.80078125, 0.8046875 , 0.80859375, 0.8125 , 0.81640625,
0.8203125 , 0.82421875, 0.828125 , 0.83203125, 0.8359375 ,
0.83984375, 0.84375 , 0.84765625, 0.8515625 , 0.85546875,
0.859375 , 0.86328125, 0.8671875 , 0.87109375, 0.875 ,
0.87890625, 0.8828125 , 0.88671875, 0.890625 , 0.89453125,
0.8984375 , 0.90234375, 0.90625 , 0.91015625, 0.9140625 ,
0.91796875, 0.921875 , 0.92578125, 0.9296875 , 0.93359375,
0.9375 , 0.94140625, 0.9453125 , 0.94921875, 0.953125 ,
0.95703125, 0.9609375 , 0.96484375, 0.96875 , 0.97265625,
0.9765625 , 0.98046875, 0.984375 , 0.98828125, 0.9921875 ,
0.99609375, 1. ]), <BarContainer object of 256 artists>)
大多数情况下,图像的“有趣”部分位于峰值附近,您可以通过裁剪峰值上方和/或下方的区域来获得额外的对比度。在我们的直方图中,高端似乎没有太多有用的信息(图像中没有很多白色的东西)。让我们调整上限,以便我们有效地“放大”直方图的一部分。我们通过将 clim 参数传递给 imshow 来做到这一点。您也可以通过调用
set_clim()
图像绘图对象的方法来执行此操作,但请确保在使用 Jupyter Notebook 时在与绘图命令相同的单元格中执行此操作 - 它不会更改早期单元格的绘图。
您可以在对 的调用中指定clim plot
。
imgplot = plt.imshow(lum_img, clim=(0.0, 0.7))
您还可以使用返回的对象指定 clim
fig = plt.figure()
ax = fig.add_subplot(1, 2, 1)
imgplot = plt.imshow(lum_img)
ax.set_title('Before')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
ax = fig.add_subplot(1, 2, 2)
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0.0, 0.7)
ax.set_title('After')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
<matplotlib.colorbar.Colorbar object at 0x7f2cdf75fa30>
数组插值方案#
插值根据不同的数学方案计算像素“应该”的颜色或值。发生这种情况的一个常见地方是调整图像大小时。像素数发生变化,但您需要相同的信息。由于像素是离散的,因此缺少空间。插值是您填充该空间的方式。这就是为什么当你炸毁它们时,你的图像有时会显得像素化。当原始图像和扩展图像之间的差异更大时,效果更明显。让我们拍摄我们的图像并缩小它。我们有效地丢弃了像素,只保留了少数几个。现在,当我们绘制它时,这些数据会被放大到屏幕上的大小。旧像素不再存在,计算机必须绘制像素来填充该空间。
我们将使用我们用来加载图像的 Pillow 库来调整图像大小。
from PIL import Image
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="nearest")
和双三次:
imgplot = plt.imshow(img, interpolation="bicubic")
放大照片时经常使用双三次插值 - 人们往往更喜欢模糊而不是像素化。
脚本总运行时间:(0分8.344秒)