下面是使用Matplotlib绘制图像的简短教程。
启动命令
首先启动IPython。它是标准Python提示的最佳增强,它与Matplotlib特别相关。现在可以在shell或IPython Notebook上启动IPython。
随着IPython的启动,我们现在需要连接到GUI事件循环。这告诉IPython在哪里(以及如何)显示图。要连接到GUI循环,请在IPython提示符下执行%matplotlib magic。关于它在IPython的GUI事件循环文档中的确切内容有更详细的说明。
如果正在使用IPython Notebook,则可以使用相同的命令,但人们通常使用%matplotlib魔法的特定参数:
In [1]: %matplotlib inline
这将打开内联绘图,其中绘图图形将出现在笔记本中。这对交互性具有重要意义。对于内联绘图,输出绘图的单元格下方单元格中的命令不会影响绘图。例如,无法从创建绘图的单元格下方的单元格更改颜色贴图。但是,对于其他后端,例如Qt5,打开一个单独的窗口,创建绘图的下面的单元格将改变绘图 - 它是内存中的活动对象。
本教程将使用matplotlib的命令式绘图接口pyplot。该接口保持全局状态,对于快速轻松地试验各种绘图设置非常有用。另一种选择是面向对象的接口,它也非常强大,通常更适合大型应用程序开发。如果想了解面向对象的界面,一个很好的开始是学习使用指南。现在继续使用命令式方法:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
将图像数据导入Numpy数组
Pillow库支持加载图像数据。在本机,Matplotlib仅支持PNG图像。如果本机读取失败,下面显示的命令将回退到Pillow。
此示例中使用的图像是PNG文件,但请记住您自己的数据的Pillow要求。
下面是要使用的图像:
它是一个24位RGB PNG图像(R,G,B各有8位)。根据获取数据的位置,最有可能遇到的其他类型的图像是RGBA图像,它们允许透明度,或单通道灰度(亮度)图像。您可以右键单击它并选择“将图像另存为”以将其下载到您的计算机以完成本教程的其余部分。
现在就开始操作了…
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位/通道?因为那是人眼所能看到的。
每个内部列表代表一个像素。这里,对于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)
将伪彩色方案应用于图像图
Pseudocolor可以成为增强对比度和更容易可视化数据的有用工具。这在使用投影仪进行数据演示时尤其有用 - 它们的对比度通常非常差。
伪彩色仅与单通道,灰度,亮度图像相关。我们目前有一个RGB图像。由于R,G和B都是相似的(请参阅上面或数据),我们可以选择一个数据通道:
lum_img = img[:, :, 0]
# This is array slicing. You can read more in the `Numpy tutorial
# `_.
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')
注意 - 在具有内联后端的IPython Notebook中,无法更改已经呈现的绘图。如果在一个单元格中创建imgplot,则不能在稍后的单元格中调用set_cmap()并期望更早的绘图。确保在一个单元格中一起输入这些命令。plt命令不会更改早期单元格的图形。
imgplot = plt.imshow(lum_img)
plt.colorbar()
这会为现有的图形添加一个颜色条。如果更改切换到不同的色彩映射,则不会自动更改 - 必须重新创建绘图,然后再次添加颜色栏。
检查特定数据范围
有时,希望增强图像的对比度,或者扩大特定区域的对比度,同时牺牲颜色的细节,这些颜色不会有太大变化,或者无关紧要。找到有趣区域的好工具是直方图。要创建图像数据的直方图,我们使用hist()函数。
plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k')
大多数情况下,图像的“有趣”部分位于峰值周围,可以通过剪切峰值上方和/或下方的区域来获得额外的对比度。在我们的直方图中,看起来高端没有太多有用的信息(图像中的白色东西不多)。我们调整上限,以便有效地“放大”直方图的一部分。通过将攀登论证传递给imshow来做到这一点。也可以通过调用图像绘图对象的set_clim()方法来完成此操作,但在使用IPython Notebook时,请确保在与绘图命令相同的单元格中执行此操作 - 它不会更改早期单元格中的绘图。
可以在绘图调用中指定clim -
imgplot = plt.imshow(lum_img, clim=(0.0, 0.7))
还可以使用返回的对象指定clim -
fig = plt.figure()
a = fig.add_subplot(1, 2, 1)
imgplot = plt.imshow(lum_img)
a.set_title('Before')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
a = fig.add_subplot(1, 2, 2)
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0.0, 0.7)
a.set_title('After')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
阵列插值方案
根据不同的数学方案,插值计算像素“应该”的颜色或值。发生这种情况的一个常见地方是调整图像大小。像素数会发生变化,但您需要相同的信息。由于像素是离散的,因此缺少空间。插值就是填充那个空间的方式。这就是为什么当把它们炸掉时,图像有时看起来像是像素化的原因。当原始图像和扩展图像之间的差异更大时,效果更明显。拍摄照片并缩小它,有效地丢弃像素,只保留少数像素。现在,当我们绘制它时,数据会被炸成屏幕上的大小。旧像素不再存在,计算机必须以像素绘制以填充该空间。
加载图像的Pillow库来调整图像大小。
from PIL import Image
img = Image.open('../../doc/_static/stinkbug.png')
img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place
imgplot = plt.imshow(img)
这里有默认的插值,双线性,因为没有给imshow()插值参数。
imgplot = plt.imshow(img, interpolation="nearest")
¥ 我要打赏
纠错/补充
收藏
加QQ群啦,易百教程官方技术学习群
注意:建议每个人选自己的技术方向加群,同一个QQ最多限加 3 个群。