Python 图像处理入门:用 Pillow 快速上手

1. Pillow 简介

日常开发里,无论是生成网站缩略图、制作随机验证码,还是批量裁剪图片尺寸,都不必求助复杂的 Photoshop 脚本或第三方 API——Python 的 Pillow 库就能轻松搞定。

Pillow 是老牌 Python Imaging Library(PIL)的现代化分支:它在保留 PIL 简洁 API 的同时,完全兼容 Python 3,并额外加入了新格式支持、性能优化等特性,是目前 Python 生态中最流行的轻量级图像处理工具。

核心亮点

  • 支持超过 40 种图像格式(JPEG、PNG、BMP、GIF、TIFF、WebP 等)
  • 覆盖从基础到进阶的常见图像处理需求
  • 代码逻辑清晰,新手友好
  • 社区活跃,版本迭代稳定

2. 快速安装

标准 pip 安装

pip install pillow

Anaconda / Miniconda 环境

conda install pillow

在 Linux / macOS 上使用普通用户安装时,建议添加 --user 参数,避免修改系统环境:

pip install --user pillow

3. 基础图像操作

3.1 打开、查看与保存

这是 Pillow 最核心的第一步,代码几乎和“打开记事本”一样直观:

from PIL import Image

# 使用 with 语句自动管理文件句柄(推荐的最佳实践)
with Image.open("test.jpg") as im:
    # 打印图像元信息
    print(f"📄 格式: {im.format}")
    print(f"📐 尺寸(宽×高): {im.size[0]}×{im.size[1]}")
    print(f"🎨 色彩模式: {im.mode}")  # RGB / RGBA / L(灰度) / P(索引色) 等

    # 根据扩展名自动转换格式并保存
    im.save("output.png")

3.2 调整大小

Pillow 提供了两种常用方式:

  • thumbnail():按比例缩小,原地修改图像,保证图像不会超出指定尺寸。
  • resize():强制拉伸或缩放,返回新图像,尺寸完全可控。
with Image.open("test.jpg") as im:
    w, h = im.size  # 解包元组更方便

    # 方式1:生成宽不超过800的缩略图(保持纵横比)
    im.thumbnail((800, 800))
    im.save("thumbnail_800w.jpg", quality=95)  # JPEG 质量 1-100,推荐 85-95

    # 方式2:强制调整为 600×400(会变形,适合需要固定尺寸的场景)
    fixed_size_im = im.resize((600, 400))
    fixed_size_im.save("fixed_600x400.jpg")

💡 注意:thumbnail() 会直接修改原图像,而 resize() 返回全新图像。如果后续还需要使用原始尺寸,请先做好复制。

3.3 旋转与翻转

旋转和翻转都是返回新图像的非原地操作:

with Image.open("test.jpg") as im:
    # 逆时针旋转45度,expand=True 会自动扩大画布以容纳旋转后的图像
    rotated_45 = im.rotate(45, expand=True)

    # 水平 / 垂直翻转
    flip_h = im.transpose(Image.FLIP_LEFT_RIGHT)
    flip_v = im.transpose(Image.FLIP_TOP_BOTTOM)

    rotated_45.save("rotated_45_expanded.png")

4. 一键套用内置滤镜

Pillow 内置了十几种常用滤镜,无需手写复杂的图像处理算法:

from PIL import Image, ImageFilter

with Image.open("test.jpg") as im:
    # 挑选几个常用滤镜演示
    filters = [
        ("blur", ImageFilter.BLUR),       # 模糊
        ("contour", ImageFilter.CONTOUR), # 轮廓提取
        ("emboss", ImageFilter.EMBOSS),   # 浮雕
        ("sharpen", ImageFilter.SHARPEN), # 锐化
    ]

    # 批量应用滤镜并保存
    for name, f in filters:
        filtered = im.filter(f)
        filtered.save(f"filtered_{name}.jpg")

5. 简单图像绘制

结合 ImageDrawImageFont,你可以轻松生成验证码、文字水印、简易图表等。

5.1 基础图形绘制

from PIL import Image, ImageDraw

# 创建一张白色 RGB 画布 (400×300)
canvas = Image.new("RGB", (400, 300), color="white")
draw = ImageDraw.Draw(canvas)

# 画红色对角线(坐标:x1, y1, x2, y2)
draw.line((0, 0, 400, 300), fill="red", width=3)

# 画绿色填充、蓝色边框的矩形(坐标:左, 上, 右, 下)
draw.rectangle((100, 100, 300, 200), fill="#00FF00", outline="#0000FF", width=2)

# 画蓝色圆形(实际上是宽高相等的椭圆)
draw.ellipse((150, 50, 250, 150), fill="blue")

canvas.save("basic_drawing.png")

5.2 实用小工具:生成 4 位验证码

很多网站的验证码逻辑都可以用这个简化版实现:

from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random

def gen_captcha(width=240, height=60, char_len=4):
    # 1. 创建浅灰色背景画布
    bg_color = (240, 240, 240)
    img = Image.new("RGB", (width, height), bg_color)
    draw = ImageDraw.Draw(img)

    # 2. 加载字体(找不到系统字体时会回退到默认位图字体)
    try:
        # Windows 路径示例:C:/Windows/Fonts/arial.ttf
        # macOS 路径示例:/Library/Fonts/Arial.ttf
        # Linux 路径示例:/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
        font = ImageFont.truetype("arial.ttf", size=40)
    except IOError:
        font = ImageFont.load_default()

    # 3. 生成随机大写字母
    captcha_text = "".join([chr(random.randint(65, 90)) for _ in range(char_len)])

    # 4. 计算文本尺寸并居中绘制(每个字母带轻微随机偏移)
    #    使用 textbbox 兼容 Pillow 8.0+
    bbox = draw.textbbox((0, 0), captcha_text, font=font)
    text_w, text_h = bbox[2] - bbox[0], bbox[3] - bbox[1]
    start_x = (width - text_w) // 2
    start_y = (height - text_h) // 2

    for i, char in enumerate(captcha_text):
        x_offset = random.randint(-5, 5)
        y_offset = random.randint(-3, 3)
        draw.text(
            (start_x + i * (text_w // char_len) + x_offset, start_y + y_offset),
            char,
            font=font,
            fill=(random.randint(0, 100), random.randint(0, 100), random.randint(0, 100))
        )

    # 5. 轻微模糊,增加识别难度
    img = img.filter(ImageFilter.GaussianBlur(radius=1.2))

    return img, captcha_text

# 调用示例
if __name__ == "__main__":
    captcha_img, code = gen_captcha()
    captcha_img.save("my_captcha.jpg")
    print(f"✅ 验证码已生成,内容为:{code}")

6. 进阶小功能

6.1 带透明度的图像合成

将带有透明通道的 PNG 水印叠加到照片上,常用于批量添加品牌标识:

from PIL import Image

with Image.open("photo.jpg") as bg, Image.open("watermark.png") as wm:
    # 确保水印为 RGBA 模式(拥有透明通道)
    if wm.mode != "RGBA":
        wm = wm.convert("RGBA")

    # 将水印缩小为照片宽度的 1/4,放置在右下角
    bg_w, bg_h = bg.size
    wm.thumbnail((bg_w // 4, bg_h // 4))

    # 计算右下角坐标(留出 20px 边距)
    paste_x = bg_w - wm.size[0] - 20
    paste_y = bg_h - wm.size[1] - 20

    # 带透明度叠加:第三个参数传入水印自身,利用其 alpha 通道遮罩
    bg.paste(wm, (paste_x, paste_y), wm)
    bg.save("photo_with_watermark.jpg")

7. 常见问题速查

  1. 系统字体加载失败
    将字体路径替换为对应系统的真实绝对路径,或直接使用 ImageFont.load_default() 加载默认位图字体。

  2. RGBA 图片直接保存为 JPEG 报错
    JPEG 格式不支持透明度,需要先转换为 RGB 模式:

    if im.mode == "RGBA":
        im = im.convert("RGB")
  3. 处理大图时内存溢出
    优先使用 thumbnail() 按比例缩小图片,避免对超大尺寸图像直接调用 resize()

8. 学习资源

通过本教程,你已经掌握了 Pillow 80% 的核心使用场景,剩下的细节可以根据官方文档按需探索!