Pillow 图像处理完全指南
背景
从用户头像裁剪到批量水印添加,从验证码生成到图像格式转换,Pillow 几乎覆盖了 Web 开发中所有图像处理需求。它也是 scikit-image、torchvision 等更高级库的图像读写基础。
第 1 章:图像基本操作
from PIL import Image
# 打开与属性
img = Image.open("photo.jpg")
print(img.format) # JPEG
print(img.size) # (1920, 1080)
print(img.mode) # RGB
print(img.info) # 元数据字典
# 格式转换
img.save("photo.png", "PNG")
img.save("photo.webp", "WEBP", quality=80)
# 图像模式转换
gray = img.convert("L") # 灰度
rgba = img.convert("RGBA") # 透明通道
cmyk = img.convert("CMYK") # 印刷色
第 2 章:ImageDraw 绘图
from PIL import Image, ImageDraw, ImageFont
img = Image.new("RGB", (800, 600), color=(30, 30, 30))
draw = ImageDraw.Draw(img)
# 基本形状
draw.rectangle([50, 50, 300, 200], fill=(60, 120, 200), outline="white", width=3)
draw.ellipse([400, 300, 700, 500], fill=(200, 60, 60))
draw.line([(50, 400), (750, 400)], fill="yellow", width=5)
draw.polygon([(400, 100), (550, 50), (600, 150)], fill="green")
# 文字
font = ImageFont.truetype("arial.ttf", size=48)
draw.text((250, 550), "Hello, Pillow!", fill="white", font=font)
img.save("drawing.png")
第 3 章:像素级操作
# 逐像素访问(慢,适用于小图)
pixels = img.load()
for y in range(img.height):
for x in range(img.width):
r, g, b = pixels[x, y]
# 替换所有接近白色的像素为透明
if r > 240 and g > 240 and b > 240:
pixels[x, y] = (0, 0, 0, 0)
# 批量像素操作(快,使用 NumPy)
import numpy as np
arr = np.array(img)
arr[arr > 200] = 255 # 高通阈值
result = Image.fromarray(arr)
第 4 章:批量处理实战
import os
from PIL import Image, ImageOps
from pathlib import Path
def batch_process(input_dir, output_dir, size=(800, 800)):
"""批量缩略图 + 灰度 + 增强对比度"""
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
for filepath in Path(input_dir).glob("*.*"):
if filepath.suffix.lower() not in {".jpg", ".jpeg", ".png", ".webp"}:
continue
with Image.open(filepath) as img:
# 转换为 RGB(统一格式)
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
# 缩略图
img.thumbnail(size)
# 自动对比度
img = ImageOps.autocontrast(img)
# 保存
out_path = output_dir / f"processed_{filepath.stem}.jpg"
img.save(out_path, "JPEG", quality=85, optimize=True)
print(f"✓ {out_path}")
batch_process("./raw_photos", "./processed_photos")
第 5 章:与 Web 框架集成
# Flask 示例:上传并生成头像缩略图
from flask import Flask, request
from PIL import Image
from io import BytesIO
@app.route("/upload-avatar", methods=["POST"])
def upload_avatar():
file = request.files["avatar"]
img = Image.open(file.stream)
# 裁剪为正方形中心
w, h = img.size
size = min(w, h)
left = (w - size)
top = (h - size)
img = img.crop((left, top, left + size, top + size))
# 三档缩略图
sizes = {"lg": 512, "md": 128, "sm": 64}
urls = {}
for name, px in sizes.items():
thumb = img.resize((px, px), Image.LANCZOS)
buf = BytesIO()
thumb.save(buf, "JPEG", quality=85)
buf.seek(0)
# 上传到 S3 / 保存到磁盘...
urls[name] = f"/avatars/{name}_{user_id}.jpg"
return {"urls": urls}
思考题
Image.thumbnail() 和 Image.resize() 有什么区别?何时用哪个?
- 如何在 Pillow 中实现图片的颜色直方图均衡化?
- 处理超大图片(>10000x10000)时,Pillow 有哪些内存优化技巧?