Python 图像处理实战

从表情包制作入手:Python 图像处理入门实战

想象这样一个场景:你想把猫主子的美照一键缩成朋友圈缩略图、自动打上可爱水印、给猫脸画个俏皮轮廓,甚至生成一张专属的静态节日贺卡——这些看上去有点“设计师”的需求,用 Python 竟然能轻松搞定。而背后那个只用几行代码就能让你变身“图像魔术师”的库,就是 Pillow

Daoman Python AI 的实战项目里,Pillow 一直被当作数据预处理和视觉工具链的“瑞士军刀级入门库”。先玩透它,再去碰 OpenCV、TensorFlow Lite 这类硬核框架,上手会顺滑很多。


1. 两分钟扫盲:图像的「最小零件」

在敲代码之前,有两个核心概念必须速刷一下。原理虽然简单,但踩过坐标坑的人都懂它们的重要性。

1.1 颜色模型(RGB/RGBA)

计算机屏幕靠红 (Red)、绿 (Green)、蓝 (Blue) 三种色光叠加来显示五彩斑斓的世界,这就是 RGB 颜色模型。

  • 每种色光的强度用 0~255 之间的整数表示(256 级灰度),数值越大,颜色越亮。
  • RGBA 在此基础上多了一个 Alpha 通道,同样取 0~255,代表透明度(0 完全透明,255 完全不透明)。做水印、贴纸合成时,这个通道至关重要。

速查小卡片

常用名称RGB 值常用名称RGB 值
纯白(255, 255, 255)纯红(255, 0, 0)
纯绿(0, 255, 0)纯蓝(0, 0, 255)
中灰(128, 128, 128)亮黄(255, 255, 0)
纯黑(0, 0, 0)暗紫(128, 0, 128)

1.2 像素(Pixel)

把一张照片或截图不断放大到极致,你看到的就是密密麻麻的小色块——这就是像素,图像的最小可编辑单元。一张 1920×1080 的图片,总共有超过 200 万个这样的色块,Pillow 的所有操作,说白了就是在帮我们批量处理这些“小格子”。


2. Pillow 快速上手:从安装到「花式修图」

Pillow 是 PIL (Python Imaging Library) 的现代化复刻版,兼容性好、API 设计得特别直觉,是目前 Python 3.x 处理图像的首选。

安装一步到位

pip install pillow

2.1 基础五连招:打开 → 看信息 → 裁剪 → 缩放 → 转存

核心模块是 PIL.Image。下面这段流程和你用 PS 或手机修图 App 的思路如出一辙,建议配合自己的图片(比如命名为 cat_hero.jpg)一起跑一遍。

from PIL import Image

# 1. 打开图片(本地路径;如果是网络图片,需要先用 requests 拉取二进制流)
try:
    img = Image.open("cat_hero.jpg")
    img.show()  # 弹出系统默认图片查看器,快速确认图片内容
except FileNotFoundError:
    print("❌ 图片不存在,请检查路径!")

# 2. 获取基础属性
print(f"✅ 图片格式:{img.format}")   # JPEG、PNG、BMP 等
print(f"✅ 图片尺寸(宽, 高):{img.size}")   # 元组 (w, h)
print(f"✅ 颜色模式:{img.mode}")   # RGB、RGBA、L(灰度) 等

# 3. 裁剪(牢牢记住:Pillow 坐标原点在左上角,x 轴向右,y 轴向下)
# crop() 参数格式:(左边界, 上边界, 右边界, 下边界)
# 注意:右边界和下边界是“取不到”的,范围是 [左, 右) 与 [上, 下)
crop_area = (100, 50, 500, 400)
cat_face = img.crop(crop_area)
cat_face.show()
cat_face.save("cat_face_only.png")   # 转为带透明通道的 PNG(原图若是 JPEG,裁剪区域仍无透明)

# 4. 缩放
## 方法一:thumbnail() —— 原地修改,且强制保持宽高比,非常适合生成缩略图
img_copy = img.copy()  # thumbnail 会修改原对象,复制一份保平安
img_copy.thumbnail((200, 200))  # 括号内是“最大允许尺寸”
img_copy.save("cat_thumb.jpg")

## 方法二:resize() —— 返回新图,可拉伸/压缩到任意精确尺寸
cat_face_resized = cat_face.resize((100, 100))
cat_face_resized.show()

# 5. 旋转与翻转(均返回新图,不会修改原图)
## 旋转 45°(逆时针),expand=True 会自动扩大画布,避免边角被切
img_rotated = img.rotate(45, expand=True)
img_rotated.show()

## 水平 / 垂直镜像
img_flip_h = img.transpose(Image.FLIP_LEFT_RIGHT)   # 水平翻转
img_flip_v = img.transpose(Image.FLIP_TOP_BOTTOM)   # 垂直翻转
img_flip_h.save("cat_mirror.jpg")

2.2 进阶玩法:滤镜 + 贴纸合成

Pillow 内置了一大堆即开即用的滤镜,外加灵活的粘贴功能,让你轻松做出“猫片表情包”。

from PIL import ImageFilter

# 用前面的 cat_face_only.jpg 或 cat_hero.jpg 试试效果
img_blur = img.filter(ImageFilter.GaussianBlur(radius=5))   # 高斯模糊,radius 越大越朦胧
img_contour = img.filter(ImageFilter.CONTOUR)   # 轮廓提取,做表情包常用!
img_sharpen = img.filter(ImageFilter.SHARPEN)   # 锐化
img_contour.show()

贴纸合成:给猫主子加个爱心

# 准备一张带透明通道的爱心贴纸(如果没有,代码会自动帮你画一个半透明红圆充数)
try:
    heart_sticker = Image.open("heart.png").convert("RGBA")   # 强制转 RGBA
except FileNotFoundError:
    from PIL import ImageDraw
    # 临时生成一张 100x100 的透明画布,并在上面画个半透明红色圆形
    heart_sticker = Image.new("RGBA", (100, 100), (0, 0, 0, 0))  # 完全透明背景
    heart_draw = ImageDraw.Draw(heart_sticker)
    heart_draw.ellipse((0, 0, 100, 100), fill=(255, 0, 0, 200))  # 半透明红

# 把爱心缩小一点
heart_sticker_resized = heart_sticker.resize((80, 80))
w, h = heart_sticker_resized.size

# 准备画布:复制原图并转 RGBA,以便承载透明元素
canvas = img.convert("RGBA")
# 粘贴时直接把贴纸本身的 Alpha 通道作为 mask,完美保留半透明效果
canvas.paste(heart_sticker_resized,
             (img.size[0] - w - 20, img.size[1] - h - 20),
             mask=heart_sticker_resized)

# 如果要保存为 JPG,需要先转回 RGB(JPG 不支持透明通道)
canvas.convert("RGB").save("cat_with_heart.jpg")
canvas.show()

小提示
粘贴函数 paste() 的第三个参数 mask 是一个非常强大的设计:你可以用它精确控制“只贴贴纸本身,不贴背景”。对半透明边缘的处理尤其友好。


3. 静态绘图:用代码“画”一张贺卡

Pillow 不光能修图,还能在空白画布上从零创作。PIL.ImageDraw 模块让你用代码画几何图形、写文字,轻松搞定验证码、节日贺卡,或者批量生成带日期的海报。

from PIL import Image, ImageDraw, ImageFont

# 1. 创建画布(宽, 高, 背景色)
canvas_width, canvas_height = 600, 400
canvas = Image.new("RGB", (canvas_width, canvas_height), (240, 248, 255))  # 浅蓝背景
drawer = ImageDraw.Draw(canvas)

# 2. 绘制装饰(彩色竖线 + 半透明气球)
## 彩色竖线
for x in range(0, canvas_width, 20):
    color = (x % 256, (x + 50) % 256, (x + 100) % 256)
    drawer.line((x, 0, x, canvas_height), fill=color, width=10)

## 半透明气球(生成一个透明图层,画完后再贴上去)
balloon_layer = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
balloon_draw = ImageDraw.Draw(balloon_layer)
balloon_positions = [(100, 150), (300, 100), (500, 200)]
for (x, y) in balloon_positions:
    balloon_draw.ellipse((x-30, y-40, x+30, y+20), fill=(255, 192, 203, 180))  # 半透明粉色
    balloon_draw.line((x, y+20, x, y+100), fill=(128, 128, 128), width=2)

canvas.paste(balloon_layer, mask=balloon_layer)

# 3. 写文字(关键是选对字体,中文需要支持中文的 .ttf 或 .ttc 字体)
# 常用系统字体路径示例:
# Windows: C:/Windows/Fonts/simhei.ttf (黑体), C:/Windows/Fonts/msyh.ttc (微软雅黑)
# macOS: /System/Library/Fonts/STHeiti Light.ttc (华文细黑)
# Linux: /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
try:
    font_title = ImageFont.truetype("msyh.ttc", 60)
    font_subtitle = ImageFont.truetype("msyh.ttc", 30)
except IOError:
    print("⚠️ 未找到指定中文字体,将使用默认英文字体(中文会显示为方块)")
    font_title = ImageFont.load_default()
    font_subtitle = ImageFont.load_default()

# 居中写出标题和副标题(用 textbbox 精确测量文字占用的矩形区域)
text_title = "Happy Birthday!"
bbox_title = drawer.textbbox((0, 0), text_title, font=font_title)
text_width_title = bbox_title[2] - bbox_title[0]
text_height_title = bbox_title[3] - bbox_title[1]
x_title = (canvas_width - text_width_title) // 2
y_title = 50
drawer.text((x_title, y_title), text_title, fill=(255, 20, 147), font=font_title)

text_subtitle = "To My Lovely Cat 🐱"
bbox_subtitle = drawer.textbbox((0, 0), text_subtitle, font=font_subtitle)
text_width_subtitle = bbox_subtitle[2] - bbox_subtitle[0]
x_subtitle = (canvas_width - text_width_subtitle) // 2
y_subtitle = y_title + text_height_title + 30
drawer.text((x_subtitle, y_subtitle), text_subtitle, fill=(0, 0, 139), font=font_subtitle)

# 4. 保存与预览
canvas.save("cat_birthday_card.jpg")
canvas.show()

注意
Pillow 9.2.0 以后的版本推荐使用 textbbox() 来动态获取文字区域的宽高。老旧的 textsize() 方法已被标记为过时,建议逐步替换。


总结与下一步

本文实战要点速记

  1. 坐标系:原点在左上角,x 向右递增,y 向下递增。
  2. 核心模块Image(读/写/基本操作)、ImageFilter(滤镜)、ImageDraw(绘图)、ImageFont(文字渲染)。
  3. 透明图层:要保留透明效果,记得将图片转为 RGBA;粘贴时通过 mask 参数控制可见区域。

接下来可以学什么?

  • 零门槛进阶:用 Pillow 批量处理照片(比如一键转灰度、批量加水印)。
  • 进入硬核视觉领域:如果想做人脸识别、目标检测、实时视频处理,直接上车 OpenCV-Python
  • 深度学习预处理:Pillow 是 TensorFlow/Keras、PyTorch 官方示例中常用的图像预处理工具,掌握它能让你更顺畅地进入深度学习图像任务的大门。

现在,不妨打开终端,挑一张你最喜欢的照片,用 Pillow 给它添点儿属于程序员的浪漫吧!