从零开始掌握Pillow图像处理库:全面实战指南
前言
在Python图像处理领域,Pillow无疑是最受欢迎和使用最广泛的库之一。作为PIL(Python Imaging Library)的现代化分支,Pillow提供了简洁而强大的API,让开发者能够轻松完成各种图像操作任务。本教程将带你从环境搭建开始,逐步深入到Pillow的核心功能,通过大量实战代码示例,帮助你全面掌握这个强大的图像处理工具。无论你是图像处理的初学者,还是希望系统化提升技能的开发者,本教程都将为你提供详尽的学习路径和实用技巧。
第一部分:环境搭建与安装
安装前的准备工作
在开始安装Pillow之前,我们需要确保Python环境已经正确配置。Pillow支持Python 3.7及以上版本,因此请确保你的系统中安装了合适版本的Python。你可以通过在终端或命令行中输入以下命令来检查Python版本:
python --version
# 或
python3 --version
如果显示的版本号低于3.7,建议先升级Python。对于不同操作系统,Python的安装方式有所差异。Windows用户可以前往Python官方网站下载安装包,macOS用户可以使用Homebrew包管理器安装,而Linux用户通常可以通过系统包管理器(如apt、yum或dnf)来安装Python。
除了Python本身之外,某些图像格式的处理可能需要额外的系统库支持。例如,处理JPEG格式需要libjpeg库,处理PNG格式需要libpng库,处理TIFF格式需要libtiff库等。在大多数情况下,这些依赖库会在你通过pip安装Pillow时自动处理,但如果遇到安装问题,可能需要手动安装这些系统级依赖项。
使用pip安装Pillow
安装Pillow最简单的方式是通过pip包管理器。在终端中执行以下命令即可完成安装:
pip install Pillow
如果你使用的是Python 3,并且系统中同时存在Python 2和Python 3,可能需要使用pip3命令:
pip3 install Pillow
对于需要最新开发版本的用户,可以直接从GitHub仓库安装。不过需要注意的是,开发版本可能不如稳定版本稳定,不建议在生产环境中使用:
pip install git+https://github.com/python-pillow/Pillow.git
在某些企业环境或受限网络中,你可能需要配置代理才能访问PyPI:
pip install --proxy=http://proxy.example.com:8080 Pillow
验证安装成功
安装完成后,验证Pillow是否正确安装非常重要。你可以通过以下Python代码来检查Pillow的版本信息和可用功能:
import PIL
print("Pillow版本:", PIL.__version__)
# 输出示例: Pillow版本: 10.0.0
from PIL import Image
print("Image模块加载成功")
# 验证图像处理功能
test_image = Image.new("RGB", (100, 100), color="red")
print("基础图像创建测试通过")
如果上述代码能够正常执行而没有报错,说明Pillow已经成功安装到你的系统中。现在你已经完成了环境搭建,可以开始探索Pillow的强大功能了。
虚拟环境的使用建议
为了保持项目的依赖隔离和管理便捷,建议在实际项目中始终使用虚拟环境。Python 3.3及以上版本内置了venv模块,可以按以下方式创建和使用虚拟环境:
# 创建虚拟环境
python -m venv myproject_env
# 激活虚拟环境
# Windows系统
myproject_env\Scripts\activate
# macOS和Linux系统
source myproject_env/bin/activate
# 在虚拟环境中安装Pillow
pip install Pillow
# 验证虚拟环境中的安装
python -c "import PIL; print(PIL.__version__)"
使用虚拟环境的好处在于,每个项目都可以有独立的依赖版本,互不干扰。当你需要迁移项目或与他人协作时,只需导出requirements.txt文件即可复现相同的依赖环境:
# 导出依赖列表
pip freeze > requirements.txt
# 根据requirements.txt安装依赖
pip install -r requirements.txt
第二部分:核心功能详解
图像的基本操作
Pillow提供了丰富的图像操作功能,从基础的打开、保存到复杂的图像变换,都可以通过简洁的API实现。让我们从最常用的图像加载和保存开始学习。
打开和加载图像
使用Pillow加载图像非常简单,只需要几行代码就可以将图像文件读入内存。Pillow支持几乎所有常见的图像格式,包括JPEG、PNG、BMP、GIF、TIFF和WebP等:
from PIL import Image
# 最基本的图像加载方式
img = Image.open("example.jpg")
# 使用上下文管理器确保资源正确释放
with Image.open("example.jpg") as img:
# 在with块内使用图像
print("图像尺寸:", img.size)
print("图像格式:", img.format)
print("图像模式:", img.mode)
# 块结束时自动关闭文件
# 处理不同路径格式的图像
import os
# 绝对路径
abs_path = "/home/user/images/photo.png"
img1 = Image.open(abs_path)
# 相对路径(相对于当前工作目录)
rel_path = "./images/photo.png"
img2 = Image.open(rel_path)
# 使用Pathlib路径对象
from pathlib import Path
path_obj = Path("images") / "photo.png"
img3 = Image.open(path_obj)
# 从字节流加载图像(适用于网络图片或数据库存储)
from io import BytesIO
image_bytes = b'\x89PNG\r\n\x1a\n...' # 假设这是图像的字节数据
img_from_bytes = Image.open(BytesIO(image_bytes))
保存图像
保存图像同样简单,Pillow会自动根据文件扩展名确定输出格式。你也可以显式指定格式和质量参数:
from PIL import Image
# 加载图像
img = Image.open("input.jpg")
# 保存为不同格式
img.save("output.png") # 保存为PNG
img.save("output.bmp") # 保存为BMP
img.save("output.gif") # 保存为GIF
# 显式指定格式和质量参数
img.save("output_high_quality.jpg", quality=95)
img.save("output_compressed.jpg", quality=70, optimize=True)
# 保存为不同格式时调整参数
img.save("output_progressive.jpg", format="JPEG", quality=85, progressive=True)
# 将图像保存到字节流而非文件
from io import BytesIO
buffer = BytesIO()
img.save(buffer, format="JPEG")
image_bytes = buffer.getvalue()
print("图像已保存到字节流,大小:", len(image_bytes), "字节")
创建新图像
除了从文件加载,Pillow还可以从头创建新图像。这在生成验证码、图表、占位图等场景中非常有用:
from PIL import Image
# 创建纯色图像
solid_image = Image.new("RGB", (800, 600), color=(255, 0, 0)) # 红色背景
# 创建带透明度的图像
transparent_image = Image.new("RGBA", (800, 600), color=(0, 255, 0, 128))
# 创建灰度图像
gray_image = Image.new("L", (800, 600), color=128)
# 使用模式"I"创建灰度图像(整数模式)
int_gray_image = Image.new("I", (800, 600), color=32768)
# 创建一个棋盘格图案作为示例
def create_checkerboard(width, height, square_size=50):
img = Image.new("RGB", (width, height), "white")
pixels = img.load()
for y in range(height):
for x in range(width):
if (x // square_size + y // square_size) % 2 == 0:
pixels[x, y] = (0, 0, 0) # 黑色方格
else:
pixels[x, y] = (255, 255, 255) # 白色方格
return img
checkerboard = create_checkerboard(400, 400, 40)
checkerboard.save("checkerboard.png")
图像的裁剪、缩放和旋转
图像的几何变换是图像处理中最常见的操作之一。Pillow提供了丰富的变换功能,包括裁剪、缩放、旋转、翻转等。
裁剪图像
裁剪是从图像中提取特定区域的操作,这在处理局部图像或准备训练数据时非常有用:
from PIL import Image
# 加载图像
img = Image.open("photo.jpg")
# 使用坐标进行裁剪
# box格式: (左, 上, 右, 下)
cropped_img = img.crop((100, 100, 400, 400))
cropped_img.save("cropped_region.jpg")
# 裁剪中心区域
width, height = img.size
center_width, center_height = 200, 200
left = (width - center_width) // 2
top = (height - center_height) // 2
right = left + center_width
bottom = top + center_height
center_crop = img.crop((left, top, right, bottom))
center_crop.save("center_region.jpg")
# 裁剪边缘区域(去除边框)
def crop_borders(img, border_size):
width, height = img.size
return img.crop((
border_size, # 左
border_size, # 上
width - border_size, # 右
height - border_size # 下
))
# 移除20像素的边框
trimmed_img = crop_borders(img, 20)
trimmed_img.save("trimmed.jpg")
# 按比例裁剪(保留宽高比)
def crop_to_ratio(img, target_ratio):
width, height = img.size
current_ratio = width / height
if current_ratio > target_ratio:
# 图像太宽,需要裁剪宽度
new_width = int(height * target_ratio)
left = (width - new_width) // 2
return img.crop((left, 0, left + new_width, height))
else:
# 图像太高,需要裁剪高度
new_height = int(width / target_ratio)
top = (height - new_height) // 2
return img.crop((0, top, width, top + new_height))
# 裁剪为16:9比例
wider_crop = crop_to_ratio(img, 16/9)
wider_crop.save("wide_crop.jpg")
缩放和调整图像大小
调整图像大小是最常用的操作之一,特别是在准备网页图片或训练数据时:
from PIL import Image
img = Image.open("photo.jpg")
original_width, original_height = img.size
# 基础缩放方法
resized_img = img.resize((800, 600)) # 指定目标尺寸
resized_img.save("resized_basic.jpg")
# 按比例缩放
def resize_by_percentage(img, percentage):
width, height = img.size
new_width = int(width * percentage / 100)
new_height = int(height * percentage / 100)
return img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 缩小到50%
half_img = resize_by_percentage(img, 50)
half_img.save("half_size.jpg")
# 缩放到指定宽度(保持宽高比)
def resize_by_width(img, target_width):
width, height = img.size
ratio = target_width / width
new_height = int(height * ratio)
return img.resize((target_width, new_height), Image.Resampling.LANCZOS)
# 缩放到宽度800像素
fixed_width = resize_by_width(img, 800)
fixed_width.save("fixed_width.jpg")
# 缩放到指定高度(保持宽高比)
def resize_by_height(img, target_height):
width, height = img.size
ratio = target_height / height
new_width = int(width * ratio)
return img.resize((new_width, target_height), Image.Resampling.LANCZOS)
# 缩放到高度600像素
fixed_height = resize_by_height(img, 600)
fixed_height.save("fixed_height.jpg")
# 使用缩略图方法(原地修改,更节省内存)
thumbnail_img = img.copy()
thumbnail_img.thumbnail((300, 300), Image.Resampling.LANCZOS)
# 注意:thumbnail会保持宽高比,结果可能不完全等于目标尺寸
thumbnail_img.save("thumbnail.jpg")
# 缩放并填充到目标尺寸(添加边框以达到目标尺寸)
def resize_and_pad(img, target_size, fill_color=(0, 0, 0)):
width, height = img.size
target_width, target_height = target_size
# 计算缩放比例
ratio = min(target_width / width, target_height / height)
new_width = int(width * ratio)
new_height = int(height * ratio)
# 缩放图像
resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 创建目标尺寸的画布
result = Image.new(img.mode, target_size, fill_color)
# 计算粘贴位置(居中)
paste_x = (target_width - new_width) // 2
paste_y = (target_height - new_height) // 2
# 粘贴缩放后的图像
result.paste(resized, (paste_x, paste_y))
return result
# 创建800x600的图像,不足部分用黑色填充
padded_img = resize_and_pad(img, (800, 600))
padded_img.save("padded.jpg")
旋转和翻转图像
图像的旋转变换在照片校正、方向调整等场景中经常使用:
from PIL import Image
img = Image.open("photo.jpg")
# 基本旋转
rotated_90 = img.rotate(90) # 顺时针旋转90度
rotated_90.save("rotated_90.jpg")
rotated_45 = img.rotate(45) # 旋转45度
rotated_45.save("rotated_45.jpg")
# 旋转并保持完整图像(不裁剪)
rotated_expand = img.rotate(45, expand=True)
rotated_expand.save("rotated_expand.jpg")
# 旋转并指定填充颜色
rotated_fill = img.rotate(30, fillcolor=(255, 255, 255))
rotated_fill.save("rotated_fill.jpg")
# 使用transform进行精确旋转
def rotate_image(img, angle):
return img.rotate(angle, expand=True, fillcolor=(0, 0, 0))
# 翻转图像
flipped_horizontal = img.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
flipped_horizontal.save("flipped_horizontal.jpg")
flipped_vertical = img.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
flipped_vertical.save("flipped_vertical.jpg")
# 旋转90度的便捷方法
rotated_left = img.transpose(Image.Transpose.ROTATE_270) # 左转90度
rotated_right = img.transpose(Image.Transpose.ROTATE_90) # 右转90度
# 旋转180度
rotated_180 = img.transpose(Image.Transpose.ROTATE_180)
rotated_180.save("rotated_180.jpg")
# 自动旋转图像(根据EXIF信息)
def auto_rotate(img):
try:
exif = img.getexif()
if exif:
orientation = exif.get(0x0112) # EXIF Orientation tag
rotations = {
2: Image.Transpose.FLIP_LEFT_RIGHT,
3: Image.Transpose.ROTATE_180,
4: Image.Transpose.FLIP_TOP_BOTTOM,
5: Image.Transpose.TRANSPOSE,
6: Image.Transpose.ROTATE_270,
7: Image.Transpose.TRANSVERSE,
8: Image.Transpose.ROTATE_90,
}
if orientation in rotations:
return img.transpose(rotations[orientation])
except Exception:
pass
return img
auto_rotated = auto_rotate(img)
auto_rotated.save("auto_rotated.jpg")
颜色和滤镜处理
Pillow提供了丰富的颜色处理和滤镜功能,可以对图像进行各种艺术效果和色彩调整。
颜色模式转换
不同的颜色模式适用于不同的用途,例如RGB用于屏幕显示,灰度模式适合文本识别,L模式适合某些算法处理:
from PIL import Image
img = Image.open("photo.jpg")
# 转换为灰度图像
gray_img = img.convert("L") # L = 灰度(8位)
gray_img.save("photo_gray.jpg")
# 转换为RGB模式(确保三个通道)
rgb_img = img.convert("RGB")
rgb_img.save("photo_rgb.jpg")
# 转换为RGBA模式(添加Alpha通道)
rgba_img = img.convert("RGBA")
rgba_img.save("photo_rgba.png")
# 转换为CMYK模式(印刷)
cmyk_img = img.convert("CMYK")
cmyk_img.save("photo_cmyk.jpg")
# 将透明背景图像与背景色合成
def composite_with_background(foreground, background, position=(0, 0)):
if foreground.mode == "RGBA":
background = background.convert("RGBA")
background.paste(foreground, position, foreground)
return background.convert("RGB")
else:
background.paste(foreground, position)
return background
# 从灰度模式转换回RGB
gray_to_rgb = gray_img.convert("RGB")
gray_to_rgb.save("gray_to_rgb.jpg")
# 处理调色板模式图像
def ensure_rgb(img):
if img.mode == "P": # 调色板模式
img = img.convert("RGBA")
if img.mode in ("RGBA", "LA"):
background = Image.new("RGB", img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
return background
return img.convert("RGB")
rgb_image = ensure_rgb(img)
rgb_image.save("ensured_rgb.jpg")
颜色调整
Pillow的ImageEnhance模块提供了便捷的颜色和亮度调整功能:
from PIL import Image, ImageEnhance, ImageFilter, ImageOps
img = Image.open("photo.jpg")
# 亮度调整
enhancer = ImageEnhance.Brightness(img)
brighter = enhancer.enhance(1.5) # 增加50%亮度
darker = enhancer.enhance(0.5) # 减少50%亮度
# 对比度调整
enhancer = ImageEnhance.Contrast(img)
more_contrast = enhancer.enhance(1.5) # 增加50%对比度
less_contrast = enhancer.enhance(0.5) # 减少50%对比度
# 色彩饱和度调整
enhancer = ImageEnhance.Color(img)
more_colorful = enhancer.enhance(1.5) # 增加50%饱和度
less_colorful = enhancer.enhance(0.5) # 减少50%饱和度
# 锐度调整
enhancer = ImageEnhance.Sharpness(img)
sharper = enhancer.enhance(2.0) # 加锐
blurrier = enhancer.enhance(0.5) # 模糊
# 组合多种调整
def adjust_image(img, brightness=1.0, contrast=1.0, color=1.0, sharpness=1.0):
if brightness != 1.0:
img = ImageEnhance.Brightness(img).enhance(brightness)
if contrast != 1.0:
img = ImageEnhance.Contrast(img).enhance(contrast)
if color != 1.0:
img = ImageEnhance.Color(img).enhance(color)
if sharpness != 1.0:
img = ImageEnhance.Sharpness(img).enhance(sharpness)
return img
# 应用组合调整
adjusted = adjust_image(img, brightness=1.1, contrast=1.2, color=0.9, sharpness=1.5)
adjusted.save("adjusted_photo.jpg")
# 自动色阶调整(类似Photoshop的自动色阶)
auto_adjusted = ImageOps.autocontrast(img, cutoff=2)
auto_adjusted.save("auto_contrast.jpg")
# 均衡化直方图
equalized = ImageOps.equalize(img)
equalized.save("equalized.jpg")
# 反相颜色
inverted = ImageOps.invert(img.convert("RGB"))
inverted.save("inverted.jpg")
应用滤镜效果
Pillow内置了多种滤镜效果,可以轻松实现各种图像处理效果:
from PIL import Image, ImageFilter, ImageEnhance
img = Image.open("photo.jpg")
# 模糊滤镜
blurred = img.filter(ImageFilter.BLUR)
blurred.save("blurred.jpg")
# 更强的模糊
more_blurred = img.filter(ImageFilter.GaussianBlur(radius=10))
more_blurred.save("gaussian_blur.jpg")
# 边缘检测滤镜
edges = img.convert("L").filter(ImageFilter.FIND_EDGES)
edges.save("edges.jpg")
# 轮廓滤镜
contour = img.filter(ImageFilter.CONTOUR)
contour.save("contour.jpg")
# 细节增强
detailed = img.filter(ImageFilter.DETAIL)
detailed.save("detailed.jpg")
# 边缘增强
edge_enhanced = img.filter(ImageFilter.EDGE_ENHANCE)
edge_enhanced.save("edge_enhanced.jpg")
# 边缘增强(更强)
edge_enhanced_more = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
# 浮雕效果
emboss = img.filter(ImageFilter.EMBOSS)
emboss.save("emboss.jpg")
# 锐化滤镜
sharpened = img.filter(ImageFilter.SHARPEN)
sharpened.save("sharpened.jpg")
# 平滑滤镜(轻微模糊)
smooth = img.filter(ImageFilter.SMOOTH)
smooth_more = img.filter(ImageFilter.SMOOTH_MORE)
# 中值滤镜(降噪)
denoised = img.filter(ImageFilter.MedianFilter(size=3))
denoised.save("denoised.jpg")
# 模式滤镜
from PIL import ImageFilter
class CustomFilter(ImageFilter.Filter):
name = "Custom Filter"
def __init__(self):
selfkernel = None
def filter(self, image):
return image.filter(ImageFilter.SMOOTH)
# 创建自定义核滤镜
from PIL import ImageFilter
kernel_3x3 = [-1, -1, -1,
-1, 9, -1,
-1, -1, -1]
sharpen_kernel = ImageFilter.Kernel(
size=(3, 3),
kernel=kernel_3x3,
scale=1,
offset=0
)
sharpened_custom = img.filter(sharpen_kernel)
sharpened_custom.save("custom_sharp.jpg")
绘图和文字处理
Pillow的ImageDraw模块允许在图像上绘制各种形状和文字,这在创建注释、验证码、水印等场景中非常有用:
from PIL import Image, ImageDraw, ImageFont
# 创建一个空白图像用于绘图
canvas = Image.new("RGB", (800, 600), "white")
draw = ImageDraw.Draw(canvas)
# 绘制矩形
draw.rectangle([100, 100, 300, 200], outline="black", width=2)
draw.rectangle([400, 100, 600, 200], fill="blue", outline="red", width=3)
# 绘制圆形和椭圆
draw.ellipse([100, 250, 250, 400], fill="red", outline="black", width=2)
draw.ellipse([350, 250, 500, 400], outline="green", width=3)
# 绘制直线
draw.line([(50, 450), (750, 450)], fill="black", width=5)
draw.line([(400, 100), (400, 550)], fill="gray", width=2)
# 绘制多边形
points = [(600, 250), (700, 400), (500, 400)]
draw.polygon(points, fill="yellow", outline="black")
# 绘制弧线
draw.arc([50, 500, 200, 650], start=0, end=180, fill="purple", width=5)
# 绘制弦(封闭弧线)
draw.chord([250, 500, 400, 650], start=0, end=180, fill="cyan", outline="black")
# 绘制弦(扇形)
draw.pieslice([450, 500, 600, 650], start=0, end=90, fill="orange")
# 添加文字
def draw_text_centered(draw, position, text, font_size=36, fill="black"):
try:
font = ImageFont.truetype("arial.ttf", font_size)
except:
font = ImageFont.load_default()
draw.text(position, text, fill=fill, font=font, anchor="mm")
draw_text_centered(draw, (400, 50), "图像绘制示例", font_size=48, fill="navy")
# 在指定位置绘制文字
if False: # 使用默认字体的示例
draw.text((100, 550), "左下角文字", fill="black")
draw.text((700, 550), "右下角文字", fill="black", anchor="rm")
canvas.save("drawing_example.jpg")
# 绘制更复杂的水印效果
def add_watermark(image, text, position="bottom-right", opacity=0.3):
watermark = Image.new("RGBA", image.size, (0, 0, 0, 0))
watermark_draw = ImageDraw.Draw(watermark)
try:
font = ImageFont.truetype("arial.ttf", 36)
except:
font = ImageFont.load_default()
# 获取文字边界框
bbox = watermark_draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# 根据位置参数确定文字位置
margin = 20
if position == "bottom-right":
x = image.size[0] - text_width - margin
y = image.size[1] - text_height - margin
elif position == "bottom-left":
x = margin
y = image.size[1] - text_height - margin
elif position == "top-right":
x = image.size[0] - text_width - margin
y = margin
elif position == "top-left":
x = margin
y = margin
else: # center
x = (image.size[0] - text_width) // 2
y = (image.size[1] - text_height) // 2
# 绘制文字阴影
watermark_draw.text((x + 2, y + 2), text, fill=(0, 0, 0, int(255 * opacity)), font=font)
# 绘制实际文字
watermark_draw.text((x, y), text, fill=(255, 255, 255, int(255 * opacity)), font=font)
if image.mode != "RGBA":
image = image.convert("RGBA")
return Image.alpha_composite(image, watermark)
img_with_watermark = add_watermark(img, "© 示例水印", position="bottom-right")
img_with_watermark.save("watermarked.jpg")
图像合成与混合
图像合成是Pillow的另一个强大功能,可以将多个图像组合在一起,创建拼图、叠加效果等:
from PIL import Image, ImageChops
# 加载要合成的图像
background = Image.open("background.jpg")
foreground = Image.open("foreground.png")
# 基础粘贴操作
background.paste(foreground, (100, 100)) # 在指定位置粘贴
background.save("pasted_basic.jpg")
# 使用遮罩进行透明粘贴
if foreground.mode == "RGBA":
background.paste(foreground, (100, 100), mask=foreground.split()[3])
else:
background.paste(foreground, (100, 100))
# 混合两张图像
def blend_images(img1, img2, alpha=0.5):
# 确保两张图像尺寸相同
if img1.size != img2.size:
img2 = img2.resize(img1.size, Image.Resampling.LANCZOS)
# 转换为相同模式
if img1.mode != img2.mode:
img2 = img2.convert(img1.mode)
return Image.blend(img1, img2, alpha)
blended = blend_images(img1, img2, alpha=0.5)
blended.save("blended.jpg")
# 创建图像叠加效果
def overlay_images(base, overlay, opacity=0.5):
if overlay.mode != "RGBA":
overlay = overlay.convert("RGBA")
# 调整叠加层透明度
alpha = overlay.split()[3]
alpha_adjusted = alpha.point(lambda p: int(p * opacity))
overlay.putalpha(alpha_adjusted)
if base.mode != "RGBA":
base = base.convert("RGBA")
return Image.alpha_composite(base, overlay)
overlayed = overlay_images(background, foreground, opacity=0.7)
overlayed.save("overlayed.png")
# 使用ImageChops进行图像运算
img1 = Image.open("image1.jpg").convert("L")
img2 = Image.open("image2.jpg").convert("L")
# 差值运算(常用于检测两图差异)
diff = ImageChops.difference(img1, img2)
diff.save("difference.jpg")
# 叠加运算
result = ImageChops.add(img1, img2)
result.save("added.jpg")
# 乘法运算(变暗效果)
multiplied = ImageChops.multiply(img1, img2)
multiplied.save("multiplied.jpg")
# 屏幕运算(变亮效果)
screened = ImageChops.screen(img1, img2)
screened.save("screened.jpg")
# 创建图像拼图
def create_photo_grid(images, cols=3, padding=10, bg_color="white"):
if not images:
raise ValueError("图像列表为空")
# 计算网格尺寸
rows = (len(images) + cols - 1) // cols
# 获取单个图像尺寸(假设所有图像尺寸相同)
img_width, img_height = images[0].size
# 计算画布尺寸
canvas_width = cols * img_width + (cols + 1) * padding
canvas_height = rows * img_height + (rows + 1) * padding
# 创建画布
canvas = Image.new("RGB", (canvas_width, canvas_height), bg_color)
# 逐个粘贴图像
for idx, img in enumerate(images):
row = idx // cols
col = idx % cols
x = col * img_width + (col + 1) * padding
y = row * img_height + (row + 1) * padding
if img.mode != "RGB":
img = img.convert("RGB")
canvas.paste(img, (x, y))
return canvas
# 使用示例
images = [img.copy() for _ in range(9)]
grid = create_photo_grid(images, cols=3, padding=20)
grid.save("photo_grid.jpg")
第三部分:实战教程
实战一:批量图像处理脚本
在实际项目中,我们经常需要对大量图像进行相同的处理操作。下面创建一个功能完善的批量处理脚本:
“`python
from PIL import Image
import os
from pathlib import Path
import argparse
class BatchImageProcessor:
def init(self, input_dir, output_dir):
self.input_dir = Path(input_dir)
self.output_dir = Path(output_dir)
self.supported_formats = {“.jpg”, “.jpeg”, “.png”, “.bmp”, “.gif”, “.tiff”}
# 创建输出目录
self.output_dir.mkdir(parents=True, exist_ok=True)
def is_image_file(self, filepath):
return filepath.suffix.lower() in self.supported_formats
def resize_image(self, img, target_size, keep_aspect_ratio=True):
width, height = img.size
target_width, target_height = target_size
if keep_aspect_ratio:
ratio = min(target_width / width, target_height / height)
new_width = int(width * ratio)
new_height = int(height * ratio)
return img.resize((new_width, new_height), Image.Resampling.LANCZOS)
else:
return img.resize((target_width, target_height), Image.Resampling.LANCZOS)
def process_image(self, img_path, operations):
img = Image.open(img_path)
original_mode = img.mode
results = {}
for op_name, op_params in operations.items():
if op_name == "resize":
img_copy = img.copy()
results["resize"] = self.resize_image(img_copy, **op_params)
elif op_name == "grayscale":
results["grayscale"] = img.convert("L")
elif op_name == "rotate":
img_copy = img.copy()
results["rotate"] = img_copy.rotate(op_params.get("angle", 0),
expand=op_params.get("expand", False))
elif op_name == "thumbnail":
img_copy = img.copy()
img_copy.thumbnail(op_params.get("size", (256, 256)),
Image.Resampling.LANCZOS)
results["thumbnail"] = img_copy
return results
def save_results(self, img_path, results, naming_template="{name}_{operation}{ext}"):
Project: https://github.com/agent0ai/agent-zero
Stars: 17688
评论区