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")
# 打开图像
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")
# 打开图像
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")
# 打开图像
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")
# 创建空白画布
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")
# 创建空白画布
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")
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")
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")
# 打开背景图像和前景图像
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")
# 创建带 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")
# 创建两个示例图像
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")
# 创建一个示例图像
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")
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")
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")
点我分享笔记