Pillow 基础图像操作与数据预处理
图像的读取、显示、保存、裁剪、旋转与缩放,是所有高级图像分析任务的基础。这些看似简单的操作,实际上构成了特征提取、图像增强、以及机器学习模型输入准备的核心步骤。只有从最初的像素数据开始,理解图像在计算机中的表达方式,才能真正掌握数据分析与建模中的"图像底层逻辑"。
在图像分析和机器学习任务中,数据预处理的质量往往决定了最终结果的好坏。通过科学的预处理手段,可以有效提升输入数据的均衡性与鲁棒性,从而提高模型的泛化能力。本篇文章将带你系统掌握 Pillow 的基础图像操作与数据预处理技巧,从文件读取到数据转化的全过程,一步步构建完整的图像处理链条。
1. 图像读取与显示
1.1 打开图像
Pillow 提供了直观的图像加载方式。使用 Image.open()
函数即可打开图像文件。
下面以 scikit-image
库自带的经典"宇航员"图为例:
python
from PIL import Image
from skimage import data
# 使用 scikit-image 的示例图片
img_array = data.astronaut() # 经典"宇航员"示例图
img = Image.fromarray(img_array)
# 输出图像信息
print('format: {}\nsize: {}\nmode: {}'.format(
img.format, img.size, img.mode
))
运行后可看到图像的基本属性,包括格式、尺寸与颜色模式:
txt
format: None
size: (512, 512)
mode: RGB
format
: 文件格式(如 JPEG、PNG)
size
: 图像宽高(像素)
mode
: 颜色模式(如 RGB、L、RGBA)
这说明该图像为标准 RGB 彩色图像,宽高均为 512 像素。
1.2 显示图像
在不同环境中显示图像的方式略有不同:
python
img.show()

该方法会打开系统自带的图片查看器。
如果你在 Jupyter Notebook 中运行,则推荐:
python
from IPython.display import display
display(img)

你将看到一张清晰的宇航员照片(RGB 彩色),适合后续图像操作实验。
2. 图像保存与格式转换
读取后的图像可通过 save()
方法保存为新文件。
2.1 保存为新文件
下面的示例将图像保存为 PNG 文件:
python
img.save('output.png')

同样也可以调整保存格式与参数。例如,将图像保存为 JPEG 格式,并设定较高的质量参数:
python
img.save('output.jpg', quality=90)

quality
参数仅对 JPEG 有效,控制压缩质量(0--100,默认 75)。数值越大,文件体积越大但图像更清晰。
2.2 格式转换
当目标格式不支持透明通道(如 JPEG),需先将图像转换为 RGB
模式:
python
img.convert('RGB').save('converted.jpg')

若目标格式不支持透明度(如 JPEG),需先转为
RGB
模式。
3. 几何变换:裁剪、旋转与缩放
这些是最常见的图像几何变换操作。
3.1 图像裁剪
图像几何操作是最直观的预处理方式。使用 crop()
方法可以截取特定区域(左、上、右、下),例如::
python
box = (100, 100, 400, 400)
cropped = img.crop(box)
display(cropped)

此处 box
参数定义了裁剪矩形的左、上、右、下边界,输出的结果是一幅截取后的局部图像。
3.2 图像旋转
当我们想让图像朝某个角度旋转时,可以使用 rotate()
方法。参数为旋转角度(单位为度):
python
rotated1 = img.rotate(45)
display(rotated1)

expand=True
的设置确保旋转后的图像不会被裁剪,使得完整图像得以保留。
python
rotated2 = img.rotate(45, expand=True)
display(rotated2)

3.3 图像缩放
若要调整图像的尺寸,可使用 resize()
函数指定目标大小,例如将其缩小为 300×200 像素:
python
resized = img.resize((300, 200))
resized.show()

或按比例缩放:
python
w, h = img.size
scaled = img.resize((int(w*0.5), int(h*0.5)))
display(scaled)

在缩放时,可选参数如
Image.BILINEAR
或Image.ANTIALIAS
可以帮助提升插值质量,使结果更加平滑自然。
4. 图像模式与通道
图像的"模式"决定了其数据结构。RGB 图像包含三个通道,而灰度图仅有一个。
4.1 查看图像模式
通过 img.mode
可查看当前模式,convert()
方法则用于模式转换。例如:
python
print(img.mode)
txt
RGB
常见模式包括:
模式 | 含义 | 通道数 |
---|---|---|
L | 灰度图 | 1 |
RGB | 真彩色 | 3 |
RGBA | 含透明通道 | 4 |
CMYK | 印刷色彩模式 | 4 |
4.2 模式转换
python
gray = img.convert('L')
gray.show()

上述代码将彩色图像转为灰度图,其视觉效果更简洁,常用于特征提取或边缘检测任务。
若需要用于印刷或 CMYK 色彩空间的任务,可使用:
python
cmyk = img.convert('CMYK')
print(cmyk.mode)
txt
CMYK
每个模式代表着不同的应用场景。RGB 用于显示设备,CMYK 常见于印刷出版,而 RGBA 额外包含透明度信息。
4.3 拆分与合并通道
Pillow 允许直接拆分通道以便单独分析:
python
r, g, b = img.split() # 拆分
merged = Image.merge('RGB', (r, g, b)) # 合并
为了更直观地理解三个通道的作用,可以通过 matplotlib
将它们分别可视化:
python
from PIL import Image
from skimage import data
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})
# 加载示例图像
img = Image.fromarray(data.astronaut())
# 拆分 RGB 通道
r, g, b = img.split()
# 可视化展示
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
# 将单通道转为彩色可视化形式
axes[0].imshow(r, cmap="Reds")
axes[0].set_title("红色通道 (R)")
axes[0].axis("off")
axes[1].imshow(g, cmap="Greens")
axes[1].set_title("绿色通道 (G)")
axes[1].axis("off")
axes[2].imshow(b, cmap="Blues")
axes[2].set_title("蓝色通道 (B)")
axes[2].axis("off")
plt.tight_layout()
plt.show()

可以清晰地看到红、绿、蓝三种通道对整体图像色彩的贡献。拆分后的通道也能重新组合回完整图像:
python
merged = Image.merge('RGB', (r, g, b))
display(merged)

这证明图像的彩色信息实质上是多个单通道数据叠加的结果。
5. 批量图像处理
在深度学习或大规模图像分析任务中,往往需要对整个文件夹中的图像执行统一的操作。Pillow 的接口设计非常简洁,能够方便地完成批处理。例如,下面的代码将一个目录中的所有图片缩放至 256×256 像素,并统一转换为灰度图:

python
import os
from PIL import Image
# 定义输入与输出文件夹路径
input_dir = 'images/' # 原始图片所在目录
output_dir = 'processed/' # 处理后图片保存目录
# 如果输出目录不存在则自动创建
os.makedirs(output_dir, exist_ok=True)
# 定义要处理的图片扩展名集合
valid_exts = ('.jpg', '.png', '.bmp')
# 遍历输入文件夹中的所有文件
for file in os.listdir(input_dir):
# 判断文件扩展名是否符合要求
if file.lower().endswith(valid_exts):
# 构建文件路径
file_path = os.path.join(input_dir, file)
# 打开图像文件
img = Image.open(file_path)
# 调整图像尺寸为256x256像素
resized = img.resize((256, 256))
# 将图像转换为灰度模式(L表示8位灰度)
gray = resized.convert('L')
# 构建输出文件路径并保存
output_path = os.path.join(output_dir, file)
gray.save(output_path)
# 打印处理进度
print(f"已处理: {file}")

所有图片统一缩放为 256×256;
转为灰度图;
保存到
processed
文件夹中。
这段脚本能自动遍历整个文件夹并完成批量预处理。执行后,你将得到格式统一、尺寸一致的图像数据集,这对于后续特征提取与模型训练至关重要。
6. 图像数据与 NumPy 的融合
Pillow 图像与 NumPy 数组可以无缝互转,从而实现像素级运算或与深度学习框架(如 TensorFlow、PyTorch)的对接。通过 np.array(img)
可将图像转换为数组:
python
import numpy as np
array = np.array(img)
print(array.shape)
txt
(512, 512, 3)
输出结果 (512, 512, 3)
表示图像的高、宽与通道数。反向操作也同样简单:
python
img2 = Image.fromarray(array)
display(img2)

这样,Pillow 成为了连接传统图像处理与数值分析的桥梁。你可以使用 NumPy 对像素值进行归一化、滤波或其他矩阵操作,然后再返回到图像空间。
7. 图像归一化与增强准备
在模型训练或特征学习阶段,通常需要将像素值标准化到 [0,1] 区间,以消除亮度差异带来的影响。通过简单的数组运算即可实现:
python
array = np.array(img) / 255.0
print(array)
txt
[[[0.60392157 0.57647059 0.59215686]
[0.42745098 0.40392157 0.48627451]
[0.24705882 0.22745098 0.4 ]
...
[0.49803922 0.47058824 0.45098039]
[0.47058824 0.45882353 0.41568627]
[0.49019608 0.46666667 0.43137255]]
[[0.69411765 0.67058824 0.67058824]
[0.56470588 0.55294118 0.56078431]
[0.44313725 0.44705882 0.48627451]
...
[0.49803922 0.4627451 0.43921569]
[0.48627451 0.45098039 0.42352941]
[0.4745098 0.45490196 0.41176471]]
...
[[0.71764706 0.6627451 0.66666667]
[0.71372549 0.65490196 0.67058824]
[0.7254902 0.64313725 0.69019608]
...
[0. 0. 0.00392157]
[0.00392157 0.00392157 0.00392157]
[0. 0. 0. ]]
[[0.72156863 0.65490196 0.6745098 ]
[0.71764706 0.64705882 0.6627451 ]
[0.70588235 0.63529412 0.67058824]
...
[0. 0. 0. ]
[0.00392157 0.00392157 0.00392157]
[0. 0. 0. ]]]
归一化后的结果可以被视为浮点型矩阵,方便后续输入神经网络或进行特征统计。若结合图像增强方法(如旋转、翻转、噪声扰动),还可以有效提升模型的泛化能力。
或使用随机翻转、旋转等增强方法:
python
import numpy as np
import matplotlib.pyplot as plt
from skimage import data
from PIL import Image
# 载入示例图像并转换为数组
img = Image.fromarray(data.astronaut())
array = np.array(img)
# 进行归一化处理:将像素值缩放到 [0, 1] 区间
normalized = array / 255.0
# 可视化原图与归一化结果对比
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].imshow(array.astype(np.uint8))
axes[0].set_title("原始图像(像素0-255)")
axes[0].axis("off")
axes[1].imshow(normalized)
axes[1].set_title("归一化后图像(像素0-1)")
axes[1].axis("off")
plt.tight_layout()
plt.show()

python
# 输出示例像素值,观察归一化效果
print("原始像素示例:", array[0, 0])
print("归一化像素示例:", normalized[0, 0])
txt
原始像素示例: [154 147 151]
归一化像素示例: [0.60392157 0.57647059 0.59215686]
经过归一化处理后,原始图像中的每个像素值由 0--255 的整数变为 0--1 的浮点数,这不仅让模型更快收敛,也有助于避免梯度爆炸或消失的问题。
8. 可视化与结果展示
为了方便比对原始与处理后的图像,可使用 Matplotlib:
python
import matplotlib.pyplot as plt
gray = img.convert('L')
plt.figure(figsize=(8,4))
plt.subplot(1,2,1)
plt.title('原始图像')
plt.imshow(img)
plt.axis('off')
plt.subplot(1,2,2)
plt.title('灰度图像')
plt.imshow(gray, cmap='gray')
plt.axis('off')
plt.show()

9. 总结
Pillow 以其简洁的接口和强大的功能,成为 Python 图像处理的基础工具。从读取到保存、从几何变换到通道分解、再到批量化处理与数值融合,它覆盖了图像预处理的全流程。
掌握这些操作,不仅能帮助你更高效地准备数据集,也能让你更深入地理解图像的数学本质与结构特征。