Pillow 高级图像处理

图像滤镜与增强

内置滤镜应用 (filter())

Pillow 提供了多种内置滤镜,使用 ImageFilter 模块:

实例

from PIL import Image, ImageFilter

# 打开图像
image = Image.open("input.jpg")

# 应用模糊滤镜
blurred = image.filter(ImageFilter.BLUR)
blurred.save("blurred.jpg")

# 应用轮廓滤镜
contour = image.filter(ImageFilter.CONTOUR)
contour.save("contour.jpg")

# 应用浮雕滤镜
emboss = image.filter(ImageFilter.EMBOSS)
emboss.save("emboss.jpg")

# 查找边缘
edges = image.filter(ImageFilter.FIND_EDGES)
edges.save("edges.jpg")

# 锐化滤镜
sharpen = image.filter(ImageFilter.SHARPEN)
sharpen.save("sharpen.jpg")

# 平滑滤镜
smooth = image.filter(ImageFilter.SMOOTH)
smooth.save("smooth.jpg")

# 细节增强
detail = image.filter(ImageFilter.DETAIL)
detail.save("detail.jpg")

图像增强 (ImageEnhance 模块)

ImageEnhance 模块提供了控制亮度、对比度、色彩和锐度的工具:

实例

from PIL import Image, ImageEnhance

# 打开图像
image = Image.open("input.jpg")

# 增强亮度(factor > 1 增加亮度,< 1 降低亮度)
enhancer = ImageEnhance.Brightness(image)
brightened = enhancer.enhance(1.5)  # 增加50%亮度
brightened.save("brightened.jpg")

# 增强对比度
enhancer = ImageEnhance.Contrast(image)
contrast = enhancer.enhance(1.8)  # 增加80%对比度
contrast.save("contrast.jpg")

# 增强色彩饱和度
enhancer = ImageEnhance.Color(image)
saturated = enhancer.enhance(1.5)  # 增加50%饱和度
saturated.save("saturated.jpg")

# 增强锐度
enhancer = ImageEnhance.Sharpness(image)
sharpened = enhancer.enhance(2.0)  # 增加100%锐度
sharpened.save("sharpened.jpg")
自定义卷积核
Pillow 允许使用自定义卷积核创建特殊效果:
pythonimport numpy as np
from PIL import Image, ImageFilter

# 打开图像
image = Image.open("input.jpg")

# 创建自定义卷积核
# 这是一个锐化卷积核
kernel = ImageFilter.Kernel(
    size=(3, 3),
    kernel=[-1, -1, -1, -1, 9, -1, -1, -1, -1],
    scale=1
)
sharpened = image.filter(kernel)
sharpened.save("custom_sharpen.jpg")

# 浮雕效果卷积核
emboss_kernel = ImageFilter.Kernel(
    size=(3, 3),
    kernel=[-2, -1, 0, -1, 1, 1, 0, 1, 2],
    scale=1,
    offset=128
)
embossed = image.filter(emboss_kernel)
embossed.save("custom_emboss.jpg")

# 高斯模糊卷积核
gaussian_kernel = ImageFilter.Kernel(
    size=(5, 5),
    kernel=[1, 4, 6, 4, 1, 4, 16, 24, 16, 4, 6, 24, 36, 24, 6, 4, 16, 24, 16, 4, 1, 4, 6, 4, 1],
    scale=256
)
gaussian_blur = image.filter(gaussian_kernel)
gaussian_blur.save("custom_gaussian.jpg")

边缘检测与锐化

除了使用内置滤镜,也可以实现更高级的边缘检测和锐化效果:

实例

from PIL import Image, ImageFilter, ImageChops, ImageOps

# 打开图像
image = Image.open("input.jpg")

# Sobel 边缘检测
# 水平 Sobel 滤镜
h_sobel = ImageFilter.Kernel(
    size=(3, 3),
    kernel=[-1, 0, 1, -2, 0, 2, -1, 0, 1],
    scale=1
)
# 垂直 Sobel 滤镜
v_sobel = ImageFilter.Kernel(
    size=(3, 3),
    kernel=[-1, -2, -1, 0, 0, 0, 1, 2, 1],
    scale=1
)

h_edges = image.filter(h_sobel)
v_edges = image.filter(v_sobel)

# 合并水平和垂直边缘
edges = ImageChops.add(
    ImageChops.multiply(h_edges, h_edges),
    ImageChops.multiply(v_edges, v_edges)
)
edges.save("sobel_edges.jpg")

# 使用高频增强进行锐化(USM - Unsharp Masking)
def unsharp_mask(image, radius=2, percent=150, threshold=3):
    """应用 USM 锐化滤镜
   
    参数:
        radius: 高斯模糊的半径
        percent: 锐化强度百分比
        threshold: 应用锐化的最小亮度变化阈值
    """

    blurred = image.filter(ImageFilter.GaussianBlur(radius=radius))
    sharpened = Image.blend(image, ImageChops.subtract(image, blurred), percent/100)
    return sharpened

usm_image = unsharp_mask(image, radius=2, percent=200, threshold=5)
usm_image.save("usm_sharpened.jpg")

绘制与文字添加

基本图形绘制 (ImageDraw 模块)

实例

from PIL import Image, ImageDraw

# 创建空白画布
width, height = 800, 600
image = Image.new("RGB", (width, height), color="white")
draw = ImageDraw.Draw(image)

# 绘制线条
draw.line([(100, 100), (700, 500)], fill="black", width=5)

# 绘制矩形
draw.rectangle([(200, 200), (600, 400)], outline="red", width=3, fill="yellow")

# 绘制椭圆
draw.ellipse([(300, 150), (500, 350)], outline="blue", width=3, fill="lightblue")

# 绘制圆形
draw.ellipse([(550, 50), (650, 150)], outline="green", width=2, fill="lightgreen")

# 绘制多边形
draw.polygon([(100, 500), (300, 450), (500, 550), (250, 600)],
             outline="purple", fill="lavender")

# 绘制圆弧
draw.arc([(400, 400), (600, 500)], start=0, end=180, fill="orange", width=3)

# 绘制点
for i in range(50):
    import random
    x = random.randint(0, width)
    y = random.randint(0, height)
    draw.point((x, y), fill="black")

image.save("drawings.png")

添加文字 (text())

实例

from PIL import Image, ImageDraw, ImageFont

# 创建空白画布
image = Image.new("RGB", (800, 600), color="white")
draw = ImageDraw.Draw(image)

# 使用默认字体
draw.text((100, 100), "Hello, Pillow!", fill="black")

# 加载自定义 TrueType 字体
try:
    # 尝试加载系统字体
    # Windows: "arial.ttf", "simhei.ttf"
    # Mac: "Arial.ttf", "STHeiti Light.ttc"
    # Linux: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
    font = ImageFont.truetype("arial.ttf", size=36)
except IOError:
    # 如果找不到系统字体,使用默认字体
    font = ImageFont.load_default()

# 绘制带自定义字体的文本
draw.text((100, 200), "自定义字体文本", font=font, fill="blue")

# 绘制带描边的文本
def draw_text_with_outline(draw, text, position, font, text_color, outline_color):
    """绘制带轮廓的文本"""
    x, y = position
    # 绘制轮廓
    draw.text((x-1, y-1), text, font=font, fill=outline_color)
    draw.text((x+1, y-1), text, font=font, fill=outline_color)
    draw.text((x-1, y+1), text, font=font, fill=outline_color)
    draw.text((x+1, y+1), text, font=font, fill=outline_color)
    # 绘制主文本
    draw.text((x, y), text, font=font, fill=text_color)

draw_text_with_outline(draw, "轮廓文本效果", (100, 300), font, "red", "black")

# 获取文本大小并居中绘制
text = "居中文本"
text_width, text_height = draw.textsize(text, font=font)
position = ((800 - text_width) // 2, 400)
draw.text(position, text, font=font, fill="purple")

# 绘制多行文本
multiline_text = """这是一个
多行文本示例
使用 Pillow 库
进行绘制"""

draw.multiline_text((100, 450), multiline_text, font=font, fill="green", spacing=10, align="center")

image.save("text_drawings.png")

绘制复杂形状

实例

from PIL import Image, ImageDraw
import math

# 创建空白画布
width, height = 800, 800
image = Image.new("RGB", (width, height), color="white")
draw = ImageDraw.Draw(image)

# 绘制星形
def draw_star(draw, center, points=5, outer_radius=100, inner_radius=50, rotation=0, **kwargs):
    """绘制星形
   
    参数:
        center: 中心点坐标元组 (x, y)
        points: 星星的角数
        outer_radius: 外圆半径
        inner_radius: 内圆半径
        rotation: 旋转角度(度)
        **kwargs: 传递给 polygon() 的参数
    """

    cx, cy = center
    angle = math.pi / points
    rotation_rad = math.radians(rotation)
   
    vertices = []
    for i in range(2 * points):
        radius = outer_radius if i % 2 == 0 else inner_radius
        theta = i * angle + rotation_rad
        x = cx + radius * math.sin(theta)
        y = cy - radius * math.cos(theta)
        vertices.append((x, y))
   
    draw.polygon(vertices, **kwargs)

# 绘制星星
draw_star(draw, center=(200, 200), fill="gold", outline="orange", width=2)
draw_star(draw, center=(500, 200), points=8, rotation=22.5,
          outer_radius=120, inner_radius=40, fill="blue", outline="navy", width=2)

# 绘制心形
def draw_heart(draw, center, size=100, **kwargs):
    """绘制心形
   
    参数:
        center: 中心点坐标元组 (x, y)
        size: 心形大小
        **kwargs: 传递给 polygon() 的参数
    """

    cx, cy = center
    vertices = []
    for t in range(100):
        angle = t / 100 * 2 * math.pi
        x = 16 * math.sin(angle) ** 3
        y = 13 * math.cos(angle) - 5 * math.cos(2*angle) - 2 * math.cos(3*angle) - math.cos(4*angle)
        # 缩放和平移
        vertices.append((cx + x * size / 16, cy - y * size / 16))
   
    draw.polygon(vertices, **kwargs)

draw_heart(draw, center=(200, 500), size=150, fill="red", outline="darkred", width=3)

# 绘制螺旋
def draw_spiral(draw, center, loops=3, radius_start=5, radius_end=100, points=500, **kwargs):
    """绘制螺旋
   
    参数:
        center: 中心点坐标元组 (x, y)
        loops: 螺旋的圈数
        radius_start: 起始半径
        radius_end: 结束半径
        points: 点的数量
        **kwargs: 传递给 line() 的参数
    """

    cx, cy = center
    vertices = []
   
    for i in range(points + 1):
        # 计算当前角度和半径
        angle = i / points * loops * 2 * math.pi
        radius = radius_start + (radius_end - radius_start) * i / points
       
        x = cx + radius * math.cos(angle)
        y = cy + radius * math.sin(angle)
        vertices.append((x, y))
   
    # 绘制折线
    for i in range(len(vertices) - 1):
        draw.line([vertices[i], vertices[i+1]], **kwargs)

draw_spiral(draw, center=(500, 500), loops=5, fill="purple", width=2)

image.save("complex_shapes.png")

使用不同字体和样式

实例

from PIL import Image, ImageDraw, ImageFont
import os

# 创建空白画布
image = Image.new("RGB", (800, 600), color="white")
draw = ImageDraw.Draw(image)

# 尝试加载多种字体
fonts = {
    "default": ImageFont.load_default(),
}

# 尝试加载系统字体
try:
    fonts["arial"] = ImageFont.truetype("arial.ttf", size=36)
except IOError:
    pass

try:
    fonts["times"] = ImageFont.truetype("times.ttf", size=36)
except IOError:
    pass

try:
    fonts["simhei"] = ImageFont.truetype("simhei.ttf", size=36)  # 中文字体
except IOError:
    pass

# 绘制不同的字体样式
y_position = 50
for font_name, font in fonts.items():
    draw.text((50, y_position), f"Font: {font_name}", font=font, fill="black")
    y_position += 60

# 创建艺术文本效果
def draw_gradient_text(draw, text, position, font, start_color, end_color, steps=10):
    """绘制渐变色文本
   
    参数:
        draw: ImageDraw 对象
        text: 要绘制的文本
        position: 文本位置 (x, y)
        font: 字体对象
        start_color: 起始颜色 (r, g, b)
        end_color: 结束颜色 (r, g, b)
        steps: 渐变步数
    """

    x, y = position
    width, height = draw.textsize(text, font=font)
   
    # 计算每个字符的宽度
    char_width = width / len(text)
   
    for i, char in enumerate(text):
        # 计算当前字符的颜色
        progress = i / (len(text) - 1) if len(text) > 1 else 0
        r = int(start_color[0] + (end_color[0] - start_color[0]) * progress)
        g = int(start_color[1] + (end_color[1] - start_color[1]) * progress)
        b = int(start_color[2] + (end_color[2] - start_color[2]) * progress)
        color = (r, g, b)
       
        # 绘制当前字符
        draw.text((x + i * char_width, y), char, font=font, fill=color)

# 应用渐变文本
if "arial" in fonts:
    draw_gradient_text(
        draw,
        "渐变色文本效果",
        (50, 300),
        fonts["arial"],
        start_color=(255, 0, 0),  # 红色
        end_color=(0, 0, 255)     # 蓝色
    )

# 应用阴影文本
def draw_shadow_text(draw, text, position, font, text_color, shadow_color, offset=(3, 3)):
    """绘制带阴影的文本"""
    x, y = position
    dx, dy = offset
   
    # 绘制阴影
    draw.text((x + dx, y + dy), text, font=font, fill=shadow_color)
   
    # 绘制主文本
    draw.text((x, y), text, font=font, fill=text_color)

# 应用阴影效果
if "arial" in fonts:
    draw_shadow_text(
        draw,
        "带阴影的文本效果",
        (50, 400),
        fonts["arial"],
        text_color=(255, 255, 255),  # 白色
        shadow_color=(100, 100, 100),  # 灰色
        offset=(3, 3)
    )

image.save("font_styles.png")

图像合成与混合

图像叠加 (paste())

实例

from PIL import Image

# 打开背景图像和前景图像
try:
    background = Image.open("background.jpg")
    foreground = Image.open("foreground.png")
except IOError:
    # 如果没有图像文件,创建示例图像
    background = Image.new("RGB", (800, 600), color="lightblue")
    foreground = Image.new("RGBA", (200, 200), color=(255, 0, 0, 128))  # 半透明红色方块

# 调整前景图像大小(可选)
foreground = foreground.resize((300, 300))

# 计算粘贴位置(居中)
paste_position = (
    (background.width - foreground.width) // 2,
    (background.height - foreground.height) // 2
)

# 简单粘贴(不考虑透明度)
simple_paste = background.copy()
simple_paste.paste(foreground, paste_position)
simple_paste.save("simple_paste.png")

# 使用透明度粘贴(如果前景有 alpha 通道)
if foreground.mode == 'RGBA':
    alpha_paste = background.copy()
    alpha_paste.paste(foreground, paste_position, foreground)
    alpha_paste.save("alpha_paste.png")

透明度处理 (alpha 通道)

实例

from PIL import Image

# 创建带 alpha 通道的图像
width, height = 500, 500
image = Image.new("RGBA", (width, height), color=(0, 0, 0, 0))  # 完全透明

# 生成渐变透明效果
for y in range(height):
    for x in range(width):
        # 从左到右透明度递减(从完全不透明到完全透明)
        alpha = 255 - int(255 * x / width)
        # 颜色从上到下渐变
        r = int(255 * y / height)
        g = int(255 * (1 - y / height))
        b = 128
        image.putpixel((x, y), (r, g, b, alpha))

image.save("alpha_gradient.png")

# 将 RGB 图像转换为带 alpha 通道的图像
def add_alpha_channel(image, alpha_value=128):
    """添加 alpha 通道到 RGB 图像
   
    参数:
        image: PIL Image 对象
        alpha_value: 透明度值 (0-255)
    """

    if image.mode != 'RGBA':
        # 转换为 RGBA 模式
        rgba_image = image.convert("RGBA")
       
        # 获取像素数据
        data = rgba_image.getdata()
       
        # 设置透明度
        new_data = []
        for item in data:
            # 修改像素的 alpha 值
            if len(item) == 4:  # 已经是 RGBA
                new_data.append((item[0], item[1], item[2], alpha_value))
            else:  # RGB
                new_data.append((item[0], item[1], item[2], alpha_value))
       
        rgba_image.putdata(new_data)
        return rgba_image
    return image

# 创建一个示例 RGB 图像
rgb_image = Image.new("RGB", (300, 300), color="blue")
# 添加 alpha 通道
rgba_image = add_alpha_channel(rgb_image, alpha_value=128)
rgba_image.save("with_alpha.png")

# 创建圆形蒙版
def create_circular_mask(image, radius=None):
    """创建一个圆形蒙版
   
    参数:
        image: PIL Image 对象
        radius: 圆的半径,默认为图像较短边的一半
    """

    width, height = image.width, image.height
    center_x, center_y = width // 2, height // 2
   
    if radius is None:
        radius = min(center_x, center_y)
   
    # 创建一个新的透明图像
    mask = Image.new('L', (width, height), 0)
   
    # 创建圆形蒙版
    for y in range(height):
        for x in range(width):
            # 计算到中心的距离
            distance = ((x - center_x) ** 2 + (y - center_y) ** 2) ** 0.5
           
            # 如果在圆内,设置为不透明
            if distance <= radius:
                mask.putpixel((x, y), 255)
   
    # 应用蒙版到原图
    if image.mode != 'RGBA':
        image = image.convert('RGBA')
   
    result = Image.new('RGBA', (width, height), (0, 0, 0, 0))
    result.paste(image, (0, 0), mask)
   
    return result

# 创建一个示例图像
square_image = Image.new("RGB", (300, 300), color="green")
# 应用圆形蒙版
circular_image = create_circular_mask(square_image)
circular_image.save("circular_image.png")

混合模式 (blend())

实例

from PIL import Image, ImageChops

# 创建两个示例图像
width, height = 500, 500
image1 = Image.new("RGB", (width, height), color="blue")
image2 = Image.new("RGB", (width, height), color="yellow")

# 在图像上绘制渐变
for y in range(height):
    for x in range(width):
        # 图像1:从左到右由蓝变黑
        blue_value = max(0, 255 - int(255 * x / width))
        image1.putpixel((x, y), (0, 0, blue_value))
       
        # 图像2:从上到下由黄变红
        red_value = int(255 * y / height)
        green_value = max(0, 255 - int(255 * y / height))
        image2.putpixel((x, y), (red_value, green_value, 0))

image1.save("gradient1.png")
image2.save("gradient2.png")

# 不同混合模式

# 1. 普通混合 (blend)
blend_result = Image.blend(image1, image2, alpha=0.5)
blend_result.save("blend.png")

# 2. 添加 (add)
add_result = ImageChops.add(image1, image2)
add_result.save("add.png")

# 3. 叠加 (screen)
screen_result = ImageChops.screen(image1, image2)
screen_result.save("screen.png")

# 4. 正片叠底 (multiply)
multiply_result = ImageChops.multiply(image1, image2)
multiply_result.save("multiply.png")

# 5. 差值 (difference)
difference_result = ImageChops.difference(image1, image2)
difference_result.save("difference.png")

# 6. 排除 (invert)
invert_result = ImageChops.invert(image1)
invert_result.save("invert.png")

# 7. 亮度 (lighter)
lighter_result = ImageChops.lighter(image1, image2)
lighter_result.save("lighter.png")

# 8. 暗度 (darker)
darker_result = ImageChops.darker(image1, image2)
darker_result.save("darker.png")

# 创建自定义混合函数
def custom_blend(image1, image2, mode="soft_light"):
    """自定义混合模式
   
    参数:
        image1, image2: 要混合的两个图像
        mode: 混合模式名称
    """

    if image1.mode != image2.mode:
        raise ValueError("两个图像必须具有相同的模式")
   
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    for y in range(height):
        for x in range(width):
            r1, g1, b1 = image1.getpixel((x, y))
            r2, g2, b2 = image2.getpixel((x, y))
           
            if mode == "soft_light":
                # 实现柔光混合模式
                r = (r1 * (255 - r2) + r2 * r2 // 255) // 255
                g = (g1 * (255 - g2) + g2 * g2 // 255) // 255
                b = (b1 * (255 - b2) + b2 * b2 // 255) // 255
            elif mode == "hard_light":
                # 实现强光混合模式
                if r2 < 128:
                    r = (2 * r1 * r2) // 255
                else:
                    r = 255 - (2 * (255 - r1) * (255 - r2)) // 255
               
                if g2 < 128:
                    g = (2 * g1 * g2) // 255
                else:
                    g = 255 - (2 * (255 - g1) * (255 - g2)) // 255
               
                if b2 < 128:
                    b = (2 * b1 * b2) // 255
                else:
                    b = 255 - (2 * (255 - b1) * (255 - b2)) // 255
            elif mode == "overlay":
                # 实现叠加混合模式
                if r1 < 128:
                    r = (2 * r1 * r2) // 255
                else:
                    r = 255 - (2 * (255 - r1) * (255 - r2)) // 255
               
                if g1 < 128:
                    g = (2 * g1 * g2) // 255
                else:
                    g = 255 - (2 * (255 - g1) * (255 - g2)) // 255
               
                if b1 < 128:
                    b = (2 * b1 * b2) // 255
                else:
                    b = 255 - (2 * (255 - b1) * (255 - b2)) // 255
            else:
                # 默认:使用普通混合
                r = (r1 + r2) // 2
                g = (g1 + g2) // 2
                b = (b1 + b2) // 2
           
            result.putpixel((x, y), (r, g, b))
   
    return result

# 应用自定义混合模式
soft_light = custom_blend(image1, image2, mode="soft_light")
soft_light.save("soft_light.png")

hard_light = custom_blend(image1, image2, mode="hard_light")
hard_light.save("hard_light.png")

overlay = custom_blend(image1, image2, mode="overlay")
overlay.save("overlay.png")

蒙版应用与高级合成技术

遮罩应用

实例

from PIL import Image, ImageDraw

# 创建一个示例图像
width, height = 500, 500
image = Image.new("RGB", (width, height), color="purple")

# 创建渐变
for y in range(height):
    for x in range(width):
        # 从左上到右下的渐变
        r = int(255 * (x + y) / (width + height))
        g = int(128 * x / width)
        b = int(255 * (1 - y / height))
        image.putpixel((x, y), (r, g, b))

# 创建蒙版图像 (L 模式表示灰度图)
mask = Image.new('L', (width, height), 0)
draw = ImageDraw.Draw(mask)

# 在蒙版上绘制形状
# 中心径向渐变遮罩
center_x, center_y = width // 2, height // 2
max_distance = (width**2 + height**2)**0.5 / 2

for y in range(height):
    for x in range(width):
        # 计算点到中心的距离
        distance = ((x - center_x)**2 + (y - center_y)**2)**0.5
        # 根据距离设置透明度(越远越透明)
        alpha = max(0, int(255 * (1 - distance / max_distance)))
        mask.putpixel((x, y), alpha)

# 保存蒙版以便检查
mask.save("radial_mask.png")

# 创建空白目标图像
result = Image.new("RGBA", (width, height), (0, 0, 0, 0))

# 应用蒙版到原图
result.paste(image, (0, 0), mask)
result.save("radial_masked.png")

# 创建自定义形状蒙版
shape_mask = Image.new('L', (width, height), 0)
draw = ImageDraw.Draw(shape_mask)

# 绘制多边形蒙版
polygon_points = [
    (width//4, height//4),
    (3*width//4, height//4),
    (width, height//2),
    (3*width//4, 3*height//4),
    (width//4, 3*height//4),
    (0, height//2)
]
draw.polygon(polygon_points, fill=255)
shape_mask.save("polygon_mask.png")

# 应用多边形蒙版
poly_result = Image.new("RGBA", (width, height), (0, 0, 0, 0))
poly_result.paste(image, (0, 0), shape_mask)
poly_result.save("polygon_masked.png")

# 创建文本蒙版
text_mask = Image.new('L', (width, height), 0)
draw = ImageDraw.Draw(text_mask)

# 尝试加载自定义字体,如果失败则使用默认字体
try:
    from PIL import ImageFont
    font = ImageFont.truetype("arial.ttf", 120)
except IOError:
    font = ImageFont.load_default()

# 在蒙版上绘制文本
text = "PILLOW"
text_width, text_height = draw.textsize(text, font=font)
position = ((width - text_width) // 2, (height - text_height) // 2)
draw.text(position, text, fill=255, font=font)
text_mask.save("text_mask.png")

# 应用文本蒙版
text_result = Image.new("RGBA", (width, height), (0, 0, 0, 0))
text_result.paste(image, (0, 0), text_mask)
text_result.save("text_masked.png")

高级图像混合与合成效果

让我们探索一些更高级的图像混合与合成效果:

实例

from PIL import Image, ImageFilter, ImageChops, ImageOps
import math

# 创建两个示例图像
width, height = 500, 500
image1 = Image.new("RGB", (width, height), color="blue")
image2 = Image.new("RGB", (width, height), color="yellow")

# 在图像上绘制渐变
for y in range(height):
    for x in range(width):
        # 图像1:从左到右由蓝变黑
        blue_value = max(0, 255 - int(255 * x / width))
        image1.putpixel((x, y), (0, 0, blue_value))
       
        # 图像2:从上到下由黄变红
        red_value = int(255 * y / height)
        green_value = max(0, 255 - int(255 * y / height))
        image2.putpixel((x, y), (red_value, green_value, 0))

# 过渡混合效果
def transition_blend(image1, image2, direction="horizontal", steps=10):
    """创建两个图像之间的平滑过渡效果
   
    参数:
        image1, image2: 要混合的两个图像
        direction: 过渡方向,"horizontal" 或 "vertical"
        steps: 过渡步数
    """

    if image1.size != image2.size:
        raise ValueError("两个图像必须具有相同的大小")
   
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    for y in range(height):
        for x in range(width):
            if direction == "horizontal":
                # 水平过渡:从左到右
                blend_factor = x / width
            elif direction == "vertical":
                # 垂直过渡:从上到下
                blend_factor = y / height
            elif direction == "radial":
                # 径向过渡:从中心向外
                center_x, center_y = width // 2, height // 2
                distance = ((x - center_x)**2 + (y - center_y)**2)**0.5
                max_distance = max((width**2 + height**2)**0.5 / 2, 1)
                blend_factor = min(1.0, distance / max_distance)
            else:
                blend_factor = 0.5  # 默认为均匀混合
           
            # 获取两个图像的像素
            r1, g1, b1 = image1.getpixel((x, y))
            r2, g2, b2 = image2.getpixel((x, y))
           
            # 计算混合像素
            r = int(r1 * (1 - blend_factor) + r2 * blend_factor)
            g = int(g1 * (1 - blend_factor) + g2 * blend_factor)
            b = int(b1 * (1 - blend_factor) + b2 * blend_factor)
           
            result.putpixel((x, y), (r, g, b))
   
    return result

# 创建水平过渡
horizontal_transition = transition_blend(image1, image2, direction="horizontal")
horizontal_transition.save("horizontal_transition.png")

# 创建垂直过渡
vertical_transition = transition_blend(image1, image2, direction="vertical")
vertical_transition.save("vertical_transition.png")

# 创建径向过渡
radial_transition = transition_blend(image1, image2, direction="radial")
radial_transition.save("radial_transition.png")

# 创建棋盘格混合效果
def checkerboard_blend(image1, image2, grid_size=50):
    """创建棋盘格混合效果
   
    参数:
        image1, image2: 要混合的两个图像
        grid_size: 棋盘格的大小
    """

    if image1.size != image2.size:
        raise ValueError("两个图像必须具有相同的大小")
   
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    for y in range(height):
        for x in range(width):
            # 确定当前像素在哪个格子中
            grid_x = x // grid_size
            grid_y = y // grid_size
           
            # 根据棋盘格模式选择图像
            if (grid_x + grid_y) % 2 == 0:
                result.putpixel((x, y), image1.getpixel((x, y)))
            else:
                result.putpixel((x, y), image2.getpixel((x, y)))
   
    return result

# 创建棋盘格混合
checkerboard = checkerboard_blend(image1, image2, grid_size=50)
checkerboard.save("checkerboard_blend.png")

# 噪声混合效果
def noise_blend(image1, image2, noise_level=0.5):
    """使用噪声进行混合
   
    参数:
        image1, image2: 要混合的两个图像
        noise_level: 噪声级别 (0.0-1.0)
    """

    if image1.size != image2.size:
        raise ValueError("两个图像必须具有相同的大小")
   
    import random
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    for y in range(height):
        for x in range(width):
            # 生成随机值
            random_value = random.random()
           
            # 根据随机值和噪声级别选择图像
            if random_value < noise_level:
                result.putpixel((x, y), image1.getpixel((x, y)))
            else:
                result.putpixel((x, y), image2.getpixel((x, y)))
   
    return result

# 创建噪声混合
noise_blended = noise_blend(image1, image2, noise_level=0.5)
noise_blended.save("noise_blend.png")

# 创建流体混合效果
def fluid_blend(image1, image2, turbulence=10.0, seed=42):
    """创建流体状的混合效果
   
    参数:
        image1, image2: 要混合的两个图像
        turbulence: 湍流强度
        seed: 随机种子
    """

    if image1.size != image2.size:
        raise ValueError("两个图像必须具有相同的大小")
   
    import random
    random.seed(seed)
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    # 创建简化的Perlin噪声实现
    def noise(x, y):
        # 简化的噪声函数
        n = x + y * 57
        n = (n << 13) ^ n
        return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0)
   
    for y in range(height):
        for x in range(width):
            # 使用扭曲的坐标生成混合因子
            noise_value = noise(x / turbulence, y / turbulence)
            blend_factor = (noise_value + 1.0) / 2.0  # 标准化到0-1范围
           
            # 获取两个图像的像素
            r1, g1, b1 = image1.getpixel((x, y))
            r2, g2, b2 = image2.getpixel((x, y))
           
            # 计算混合像素
            r = int(r1 * (1 - blend_factor) + r2 * blend_factor)
            g = int(g1 * (1 - blend_factor) + g2 * blend_factor)
            b = int(b1 * (1 - blend_factor) + b2 * blend_factor)
           
            result.putpixel((x, y), (r, g, b))
   
    return result

# 创建流体混合
fluid_blended = fluid_blend(image1, image2, turbulence=20.0)
fluid_blended.save("fluid_blend.png")

创建渐变蒙版和复杂合成效果

实例

from PIL import Image, ImageDraw, ImageFilter, ImageOps
import math

# 创建一个演示图像
width, height = 600, 400
original = Image.new("RGB", (width, height), color=(30, 30, 30))

# 绘制一些形状
draw = ImageDraw.Draw(original)
draw.rectangle([(50, 50), (width-50, height-50)], outline="white", width=2)
draw.ellipse([(100, 100), (width-100, height-100)], outline="blue", width=3)
draw.line([(width//2, 50), (width//2, height-50)], fill="red", width=5)
draw.line([(50, height//2), (width-50, height//2)], fill="green", width=5)

# 保存原始图像
original.save("original_composite.png")

# 创建渐变蒙版
def create_gradient_mask(size, direction="horizontal", start=0, end=255):
    """创建渐变蒙版
   
    参数:
        size: 蒙版尺寸 (width, height)
        direction: 渐变方向 "horizontal", "vertical", "radial", "diagonal"
        start: 起始亮度值 (0-255)
        end: 结束亮度值 (0-255)
    """

    width, height = size
    mask = Image.new('L', size, 0)
   
    for y in range(height):
        for x in range(width):
            if direction == "horizontal":
                # 水平渐变
                value = start + int((end - start) * x / width)
            elif direction == "vertical":
                # 垂直渐变
                value = start + int((end - start) * y / height)
            elif direction == "radial":
                # 径向渐变
                center_x, center_y = width // 2, height // 2
                max_dist = math.sqrt((width/2)**2 + (height/2)**2)
                dist = math.sqrt((x - center_x)**2 + (y - center_y)**2)
                value = start + int((end - start) * (dist / max_dist))
            elif direction == "diagonal":
                # 对角线渐变
                value = start + int((end - start) * (x + y) / (width + height))
            else:
                value = 0
           
            # 确保值在0-255范围内
            value = max(0, min(255, value))
            mask.putpixel((x, y), value)
   
    return mask

# 创建不同方向的渐变蒙版
horizontal_mask = create_gradient_mask((width, height), direction="horizontal")
horizontal_mask.save("horizontal_mask.png")

vertical_mask = create_gradient_mask((width, height), direction="vertical")
vertical_mask.save("vertical_mask.png")

radial_mask = create_gradient_mask((width, height), direction="radial")
radial_mask.save("radial_mask.png")

diagonal_mask = create_gradient_mask((width, height), direction="diagonal")
diagonal_mask.save("diagonal_mask.png")

# 创建一个用于混合的新图像
new_image = Image.new("RGB", (width, height))
for y in range(height):
    for x in range(width):
        # 创建一个复杂的颜色模式
        r = int(255 * (0.5 + 0.5 * math.sin(x / 30)))
        g = int(255 * (0.5 + 0.5 * math.cos(y / 20)))
        b = int(255 * (0.5 + 0.5 * math.sin((x + y) / 40)))
        new_image.putpixel((x, y), (r, g, b))

new_image.save("pattern_image.png")

# 应用不同的蒙版效果
def apply_mask_blend(image1, image2, mask):
    """使用蒙版混合两个图像
   
    参数:
        image1, image2: 要混合的两个图像
        mask: 灰度蒙版图像
    """

    if image1.size != image2.size or image1.size != mask.size:
        raise ValueError("所有图像必须具有相同的大小")
   
    width, height = image1.size
    result = Image.new(image1.mode, (width, height))
   
    for y in range(height):
        for x in range(width):
            # 获取蒙版值 (0-255)
            mask_value = mask.getpixel((x, y))
            blend_factor = mask_value / 255.0
           
            # 获取两个图像的像素
            pixel1 = image1.getpixel((x, y))
            pixel2 = image2.getpixel((x, y))
           
            # 根据像素深度混合
            if len(pixel1) == 3:  # RGB
                r1, g1, b1 = pixel1
                r2, g2, b2 = pixel2
               
                r = int(r1 * (1 - blend_factor) + r2 * blend_factor)
                g = int(g1 * (1 - blend_factor) + g2 * blend_factor)
                b = int(b1 * (1 - blend_factor) + b2 * blend_factor)
               
                result.putpixel((x, y), (r, g, b))
            elif len(pixel1) == 4:  # RGBA
                r1, g1, b1, a1 = pixel1
                r2, g2, b2, a2 = pixel2
               
                r = int(r1 * (1 - blend_factor) + r2 * blend_factor)
                g = int(g1 * (1 - blend_factor) + g2 * blend_factor)
                b = int(b1 * (1 - blend_factor) + b2 * blend_factor)
                a = int(a1 * (1 - blend_factor) + a2 * blend_factor)
               
                result.putpixel((x, y), (r, g, b, a))
   
    return result

# 应用不同的蒙版混合
horizontal_blend = apply_mask_blend(original, new_image, horizontal_mask)
horizontal_blend.save("horizontal_blend.png")

vertical_blend = apply_mask_blend(original, new_image, vertical_mask)
vertical_blend.save("vertical_blend.png")

radial_blend = apply_mask_blend(original, new_image, radial_mask)
radial_blend.save("radial_blend.png")

diagonal_blend = apply_mask_blend(original, new_image, diagonal_mask)
diagonal_blend.save("diagonal_blend.png")

# 创建图案蒙版
def create_pattern_mask(size, pattern_type="grid", scale=40):
    """创建图案蒙版
   
    参数:
        size: 蒙版尺寸 (width, height)
        pattern_type: 图案类型 "grid", "dots", "stripes", "waves"
        scale: 图案的比例因子
    """

    width, height = size
    mask = Image.new('L', size, 0)
   
    for y in range(height):
        for x in range(width):
            value = 0
           
            if pattern_type == "grid":
                # 网格图案
                if x % scale < scale // 2 or y % scale < scale // 2:
                    value = 255
            elif pattern_type == "dots":
                # 点阵图案
                dist_to_center = math.sqrt(((x % scale) - scale/2)**2 +
                                        ((y % scale) - scale/2)**2)
                if dist_to_center < scale // 4:
                    value = 255
            elif pattern_type == "stripes":
                # 条纹图案
                if (x + y) % scale < scale // 2:
                    value = 255
            elif pattern_type == "waves":
                # 波浪图案
                value = int(127.5 + 127.5 * math.sin(x / scale) * math.cos(y / scale))
            else:
                value = 0
           
            mask.putpixel((x, y), value)
   
    return mask

# 创建不同的图案蒙版
grid_mask = create_pattern_mask((width, height), pattern_type="grid", scale=30)
grid_mask.save("grid_mask.png")

dots_mask = create_pattern_mask((width, height), pattern_type="dots", scale=30)
dots_mask.save("dots_mask.png")

stripes_mask = create_pattern_mask((width, height), pattern_type="stripes", scale=20)
stripes_mask.save("stripes_mask.png")

waves_mask = create_pattern_mask((width, height), pattern_type="waves", scale=40)
waves_mask.save("waves_mask.png")

# 应用图案蒙版混合
grid_blend = apply_mask_blend(original, new_image, grid_mask)
grid_blend.save("grid_blend.png")

dots_blend = apply_mask_blend(original, new_image, dots_mask)
dots_blend.save("dots_blend.png")

stripes_blend = apply_mask_blend(original, new_image, stripes_mask)
stripes_blend.save("stripes_blend.png")

waves_blend = apply_mask_blend(original, new_image, waves_mask)
waves_blend.save("waves_blend.png")