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

推荐:用 ImageMathnumpy 更高效


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 更高效
动画帧预计算 maskoffset
实时预览使用 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

需要我帮你实现 自动去水印、图像融合特效、监控摄像头变化检测、艺术风格迁移模拟 等高级功能吗?直接说需求,我给你完整代码!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注