Pillow ImageChops 模块
下面给你一个 Pillow(PIL Fork)中 ImageChops 模块 的完整入门指南,包含所有核心函数、参数详解、代码示例、创意应用、性能优化及高级技巧。
(基于 Pillow ≥ 9.0,Python 3.8+)
1. 安装 Pillow
pip install --upgrade pillow
2. 基本导入
from PIL import Image, ImageChops
3. ImageChops 核心函数一览
| 函数 | 作用 | 说明 |
|---|---|---|
invert(image) | 反相(负片) | 等效于 255 - pixel |
lighter(image1, image2) | 取较亮像素 | max(p1, p2) |
darker(image1, image2) | 取较暗像素 | min(p1, p2) |
difference(image1, image2) | 差值图 | |p1 - p2| |
add(image1, image2, scale=1.0, offset=0) | 相加 | (p1 + p2) / scale + offset |
subtract(image1, image2, scale=1.0, offset=0) | 相减 | (p1 - p2) / scale + offset |
multiply(image1, image2) | 相乘(蒙版叠加) | (p1 * p2) / 255 |
screen(image1, image2) | 滤色(变亮) | 255 - (255-p1)*(255-p2)/255 |
soft_light(image1, image2) | 柔光混合 | Photoshop 柔光模式 |
hard_light(image1, image2) | 强光混合 | Photoshop 强光模式 |
overlay(image1, image2) | 叠加混合 | Photoshop 叠加模式 |
add_modulo(image1, image2) | 环形相加 | (p1 + p2) % 256 |
subtract_modulo(image1, image2) | 环形相减 | (p1 - p2) % 256 |
blend(image1, image2, alpha) | 线性混合 | p1*(1-alpha) + p2*alpha |
composite(image1, image2, mask) | 按 mask 融合 | p1*(1-mask) + p2*mask |
offset(image, xoffset, yoffset) | 像素偏移 | 用于运动模糊等 |
4. 基础用法示例
img1 = Image.open("cat.jpg").convert("RGB")
img2 = Image.open...
4.1 图像差值(找不同)
diff = ImageChops.difference(img1, img2)
diff.save("diff.png") # 相同区域为黑,不同为亮
4.2 叠加两张图(滤色)
screen = ImageChops.screen(img1, img2)
screen.save("screen.jpg")
4.3 反相 + 柔光
inv = ImageChops.invert(img1)
soft = ImageChops.soft_light(img1, inv)
soft.save("soft_light.jpg")
5. 创意应用场景
5.1 图像找不同游戏
def find_differences(img_a, img_b, threshold=30):
diff = ImageChops.difference(img_a, img_b)
# 转灰度 + 二值化
gray = diff.convert("L")
mask = gray.point(lambda p: 255 if p > threshold else 0)
bbox = mask.getbbox() # 自动裁剪非零区域
if bbox:
return diff.crop(bbox)
return None
diff = find_differences(img1, img2)
if diff:
diff.save("差异区域.png")
5.2 蒙版叠加(水印、文字特效)
base = Image.open("bg.jpg").convert("RGB")
overlay = Image.open("logo.png").convert("RGBA")
# 提取 alpha 通道作为 mask
mask = overlay.split()[3]
# 柔光叠加 logo
result = ImageChops.soft_light(base, overlay.convert("RGB"))
result = ImageChops.composite(result, base, mask)
result.save("水印.jpg")
5.3 渐隐动画帧生成
def fade_between(img1, img2, steps=30):
frames = []
for i in range(steps):
alpha = i / (steps - 1)
frame = ImageChops.blend(img1, img2, alpha)
frames.append(frame)
return frames
frames = fade_between(img1, img2)
frames[0].save("fade.gif", save_all=True, append_images=frames[1:], duration=100, loop=0)
5.4 伪 HDR(多曝光融合)
dark = Image.open("dark.jpg")
normal = Image.open("normal.jpg")
bright = Image.open("bright.jpg")
# 取最亮区域(高光保留)
highlights = ImageChops.lighter(ImageChops.lighter(dark, normal), bright)
# 取最暗区域(阴影保留)
shadows = ImageChops.darker(ImageChops.darker(dark, normal), bright)
# 混合
hdr = ImageChops.screen(highlights, shadows)
hdr.save("伪HDR.jpg")
6. 高级技巧
6.1 批量图像平均(去噪)
def average_images(image_list):
result = image_list[0].copy()
for img in image_list[1:]:
result = ImageChops.add(result, img)
# 除以数量(使用 modulo 避免溢出)
for _ in image_list[1:]:
result = ImageChops.add_modulo(result, result) # 模拟除法
return result
# 实际更推荐用 NumPy
推荐:用
ImageMath或numpy更高效
6.2 运动模糊(offset + add)
def motion_blur(img, pixels=15, angle=45):
import math
dx = int(pixels * math.cos(math.radians(angle)))
dy = int(pixels * math.sin(math.radians(angle)))
blurred = img.copy()
for i in range(1, pixels):
offset_img = ImageChops.offset(img, dx * i // pixels, dy * i // pixels)
blurred = ImageChops.lighter(blurred, offset_img)
return blurred
blurred = motion_blur(img, 20, 30)
blurred.save("motion_blur.jpg")
6.3 图像相减去背景
bg = Image.open("background.jpg")
fg = Image.open("foreground.jpg")
# 确保尺寸一致
bg = bg.resize(fg.size)
diff = ImageChops.difference(fg, bg)
gray = diff.convert("L")
mask = gray.point(lambda p: 255 if p > 40 else 0) # 阈值去背景
# 提取前景
result = Image.composite(fg, Image.new("RGB", fg.size, "white"), mask)
result.save("去背景.png")
7. 完整示例:艺术滤镜生成器
from PIL import Image, ImageChops, ImageFilter
def artistic_filter(input_path, output_path):
img = Image.open(input_path).convert("RGB")
# 1. 反相 + 高斯模糊
inv = ImageChops.invert(img)
inv_blur = inv.filter(ImageFilter.GaussianBlur(2))
# 2. 颜色减淡(Dodge)
dodge = ImageChops.lighter(img, inv_blur)
# 3. 柔光混合
result = ImageChops.soft_light(img, dodge)
# 4. 轻微锐化
result = result.filter(ImageFilter.SHARPEN)
result.save(output_path)
artistic_filter("input.jpg", "艺术滤镜.jpg")
8. 性能优化建议
| 场景 | 建议 |
|---|---|
| 大图处理 | 先 resize 缩小处理,最后放大 |
| 批量融合 | 使用 Image.composite + numpy 更高效 |
| 动画帧 | 预计算 mask 和 offset |
| 实时预览 | 使用 thumbnail 快速测试 |
9. 常见问题 & 解决方案
| 问题 | 原因 | 解决 |
|---|---|---|
add 结果全白 | 溢出未除以 scale | 使用 scale=len(images) |
difference 全黑 | 两图完全相同 | 检查 img1.size == img2.size |
composite 不生效 | mask 不是 L 模式 | mask = mask.convert("L") |
| 颜色失真 | 模式不一致 | 都 .convert("RGB") |
10. 官方文档
- https://pillow.readthedocs.io/en/stable/reference/ImageChops.html
一键工具脚本:chops_tool.py
#!/usr/bin/env python3
import argparse
from PIL import Image, ImageChops
def main():
parser = argparse.ArgumentParser(description="ImageChops 工具箱")
parser.add_argument("img1")
parser.add_argument("img2", nargs="?")
parser.add_argument("-o", "--output", default="output.jpg")
parser.add_argument("--diff", action="store_true")
parser.add_argument("--screen", action="store_true")
parser.add_argument("--blend", type=float, help="0.0~1.0")
parser.add_argument("--invert", action="store_true")
args = parser.parse_args()
img1 = Image.open(args.img1).convert("RGB")
if args.invert:
result = ImageChops.invert(img1)
elif args.img2:
img2 = Image.open(args.img2).convert("RGB")
img2 = img2.resize(img1.size)
if args.diff:
result = ImageChops.difference(img1, img2)
elif args.screen:
result = ImageChops.screen(img1, img2)
elif args.blend is not None:
result = ImageChops.blend(img1, img2, args.blend)
else:
result = ImageChops.lighter(img1, img2)
else:
result = img1
result.save(args.output, quality=95)
print(f"已保存: {args.output}")
if __name__ == "__main__":
main()
使用示例:
# 差值图
python chops_tool.py a.jpg b.jpg --diff -o diff.png
# 渐隐 50%
python chops_tool.py a.jpg b.jpg --blend 0.5 -o blend.jpg
# 反相
python chops_tool.py photo.jpg --invert -o neg.jpg
需要我帮你实现 自动去水印、图像融合特效、监控摄像头变化检测、艺术风格迁移模拟 等高级功能吗?直接说需求,我给你完整代码!