Python图像处理库-PIL获取图像的数值矩阵

2021-04-07 11:32:26 浏览数 (1)

上一小节已经介绍了如何安装 PIL 以及 Image 类的简单使用,比如从当前路径下加载名为 shiliu.jpg 的图像。

代码语言:javascript复制
from PIL import Image

img = Image.open(r'./shiliu.jpg')
print(type(img)) # 返回Image对象
# <class 'PIL.JpegImagePlugin.JpegImageFile'>

print(img.format) # 图像的格式
# JPEG
print(img.size) # 图像的尺寸
# (1920, 1920)
print(img.mode) # 图像的模式
# RGB

我们知道 RGB 图像实际上是由三个相同形状的数值矩阵横向拼接而成的,数值矩阵中的每个元素值的范围为 (0, 255)。

RGB 图像(不同模式的数值矩阵排列可能不同)每个像素点呈现的颜色由三个数值矩阵对应位置的三个值决定,可以用一个三元组来表示,比如图示中的像素点 A 表示为 RGB(255, 0, 255),像素点 B 表示为 RGB(127, 255, 0)。换句话说,图像中的每个像素点由三元组中的三个值决定,大家比较熟悉的纯红色表示为 RGB(255, 0, 0),纯黑色表示为 RGB(0, 0, 0),纯白色表示为 RGB(255, 255, 255)

如何获取这些数值矩阵呢?PIL 提供了 PIL.Image.getdata(band = None) 方法,用来获取 Image 对象中的这些数值矩阵。getdata() 函数返回的是包含图像像素内容的 ImagingCore 对象(类似序列的一个对象),此时的 ImagingCore 对象是一个 PIL 内部的数据类型。我们可以使用 list(img.getdata()) 将其转换成 Python 的 list 对象。

代码语言:javascript复制
from PIL import Image

img = Image.open(r'./shiliu.jpg')

print(type(img.getdata()))
# <class 'ImagingCore'>

print(list(img.getdata())) # 转换为list类型
# [(76, 67, 70), (64, 55, 58), (59, 50, 53), (59, 50, 53), (56, 47, 50) ...]

getdata() 函数会将图像的像素点逐行地进行拼接,每一个像素点用 RGB 三元组表示(图像为 RGB 模式时)。

代码语言:javascript复制
pixel_width, pixel_height = img.size[0], img.size[1]
pixel = pixel_width * pixel_height

print(pixel)
# 3686400
print(len(list(img.getdata())))
# 3686400

图像的像素点与通过 getdata() 函数返回的像素点个数相同。

如果只想获取 RGB 图像三个通道中的某一个通道,可以为 getdata() 函数指定 band 参数:

  • band = None 时(默认),返回图像所有通道的像素点;
  • band = 0 时,返回第一个通道的数值,即 RGB 中的 R 通道;
  • band = 1 时,返回第二个通道的数值,即 RGB 中的 G 通道;
  • band = 2 时,返回第三个通道的数值,即 RGB 中的 B 通道;
代码语言:javascript复制
print(list(img.getdata())) # 返回图像所有通道的像素点
# [(76, 67, 70), (64, 55, 58), (59, 50, 53), (59, 50, 53), (56, 47, 50) ...]

print(list(img.getdata(band = 0))) # 返回第一个通道的数值
# [76, 64, 59, 59, 56 ...]
print(list(img.getdata(band = 1))) # 返回第二个通道的数值
# [67, 55, 50, 50, 47 ...]
print(list(img.getdata(band = 2))) # 返回第三个通道的数值
# [70, 58, 53, 53, 50 ...]

getdata() 函数会将 RGB 图像的像素点(用三元组表示)逐行地进行拼接,而指定 band 参数,返回单个通道的数值同样也是逐行进行拼接的,只不过此时不是像素点而是单个数值。简单来说,就是将对应通道的数值矩阵逐行进行拼接。

有了这些逐行拼接的像素点或单个数值,接下来可以对这些像素点或数值进行一系列的操作。

这种获取和操作图像像素的方式比较麻烦,并且在深度学习中,图像完整的数值矩阵可能更为常用。其实我们可以直接将 Image 对象转换为熟悉的 NumPy 数组,然后直接通过 NumPy 中的函数来获取和操作图像像素。

代码语言:javascript复制
import numpy as np

img_array = np.asarray(img)
print(img_array.shape)
# (1920, 1920, 3)

想要获取单个通道,只需要对数组进行索引。

代码语言:javascript复制
print(img_array[:, :, 0].shape) # R通道的数值矩阵
# (1920, 1920)
print(img_array[:, :, 1].shape) # G通道的数值矩阵
# (1920, 1920)
print(img_array[:, :, 2].shape) # B通道的数值矩阵
# (1920, 1920)

将 Image 对象转换为 NumPy 数组,我们可以不调用 Image 对象的 show() 函数来显示图像,可以直接通过 Matplotlib 模块显示图像(避免调用 Image 类对象的 show() 方法出现效率等问题) 。

代码语言:javascript复制
import matplotlib.pyplot as plt

plt.imshow(img_array)
plt.show()

0 人点赞