Pillow 图像处理详解:从入门到精通
引言
Pillow(PIL - Python Imaging Library)是 Python 中最强大的图像处理库之一。它提供了丰富的图像操作功能,包括图像打开、保存、缩放、旋转、滤镜、绘制等,是进行图像处理的必备工具。
本教程特点:
- 每个概念都配有可直接运行的代码示例
- 代码可以直接复制到 Python 解释器中执行
- 循序渐进,从基础到高级
- 包含实际应用场景和最佳实践
学习建议:
- 阅读每个示例代码
- 复制代码到 Python 解释器或 Jupyter Notebook 中运行
- 尝试修改代码,观察结果变化
- 准备一些测试图片用于实践
安装 Pillow:
pip install Pillow
第一部分:Pillow 基础
1. 导入 Pillow
# 示例 1:导入 Pillow
from PIL import Image
import os
# 查看 Pillow 版本
print(f"Pillow 版本:{Image.__version__}")
运行结果:
Pillow 版本:10.0.0
2. 打开和显示图片
# 示例 2:打开和显示图片
from PIL import Image
# 打开图片
img = Image.open('example.jpg') # 替换为你的图片路径
# 显示图片信息
print(f"图片格式:{img.format}")
print(f"图片模式:{img.mode}")
print(f"图片尺寸:{img.size}") # (宽度, 高度)
print(f"图片宽度:{img.width}")
print(f"图片高度:{img.height}")
# 显示图片(在某些环境中)
# img.show()
# 注意:如果没有图片文件,可以先创建一个测试图片
# 创建测试图片的代码在后面的示例中
运行结果:
图片格式:JPEG
图片模式:RGB
图片尺寸:(800, 600)
图片宽度:800
图片高度:600
3. 创建测试图片
# 示例 3:创建测试图片用于练习
from PIL import Image, ImageDraw, ImageFont
import os
# 创建测试目录
test_dir = 'test_images'
os.makedirs(test_dir, exist_ok=True)
# 创建一个简单的测试图片
img = Image.new('RGB', (400, 300), color='lightblue')
img.save(os.path.join(test_dir, 'test_image.jpg'))
print(f"✓ 已创建测试图片:{test_dir}/test_image.jpg")
# 创建一个带颜色的图片
img2 = Image.new('RGB', (200, 200), color=(255, 0, 0)) # 红色
img2.save(os.path.join(test_dir, 'red_image.jpg'))
print(f"✓ 已创建红色图片:{test_dir}/red_image.jpg")
# 创建一个透明背景的图片
img3 = Image.new('RGBA', (200, 200), color=(0, 0, 0, 0)) # 透明
img3.save(os.path.join(test_dir, 'transparent_image.png'))
print(f"✓ 已创建透明图片:{test_dir}/transparent_image.png")
第二部分:图片基本操作
1. 保存图片
# 示例 4:保存图片
from PIL import Image
import os
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightgreen')
# 保存为不同格式
img.save('output.jpg', 'JPEG')
img.save('output.png', 'PNG')
img.save('output.bmp', 'BMP')
print("✓ 图片已保存为多种格式")
# 保存时指定质量(仅对 JPEG 有效)
img.save('output_high_quality.jpg', 'JPEG', quality=95)
img.save('output_low_quality.jpg', 'JPEG', quality=20)
print("✓ 已保存不同质量的 JPEG 图片")
2. 图片模式转换
# 示例 5:图片模式转换
from PIL import Image
# 创建 RGB 图片
img_rgb = Image.new('RGB', (100, 100), color='red')
# 转换为灰度图
img_gray = img_rgb.convert('L')
print(f"RGB 模式:{img_rgb.mode}")
print(f"灰度模式:{img_gray.mode}")
# 转换为 RGBA(添加透明通道)
img_rgba = img_rgb.convert('RGBA')
print(f"RGBA 模式:{img_rgba.mode}")
# 保存转换后的图片
img_gray.save('grayscale.png')
img_rgba.save('rgba.png')
print("✓ 已保存转换后的图片")
3. 获取和修改像素
# 示例 6:获取和修改像素
from PIL import Image
# 创建一个图片
img = Image.new('RGB', (5, 5), color='white')
# 获取像素值
pixel = img.getpixel((0, 0))
print(f"位置 (0,0) 的像素值:{pixel}")
# 修改像素值
img.putpixel((2, 2), (255, 0, 0)) # 设置为红色
img.putpixel((1, 1), (0, 255, 0)) # 设置为绿色
img.putpixel((3, 3), (0, 0, 255)) # 设置为蓝色
# 批量修改像素
pixels = img.load()
for x in range(5):
pixels[x, 0] = (255, 0, 0) # 第一行设为红色
print("✓ 像素已修改")
img.save('modified_pixels.png')
第三部分:图片变换
1. 缩放图片
# 示例 7:缩放图片
from PIL import Image
# 创建测试图片
img = Image.new('RGB', (400, 300), color='lightblue')
# 方法1:使用 resize(指定新尺寸)
img_resized = img.resize((200, 150))
print(f"原始尺寸:{img.size}")
print(f"缩放后尺寸:{img_resized.size}")
# 方法2:使用 thumbnail(保持比例,最大尺寸)
img_thumb = img.copy()
img_thumb.thumbnail((200, 200)) # 缩放到不超过 200x200
print(f"缩略图尺寸:{img_thumb.size}")
# 方法3:使用缩放因子
width, height = img.size
img_scaled = img.resize((width // 2, height // 2))
print(f"缩小一半后尺寸:{img_scaled.size}")
# 保存
img_resized.save('resized.jpg')
img_thumb.save('thumbnail.jpg')
print("✓ 已保存缩放后的图片")
运行结果:
原始尺寸:(400, 300)
缩放后尺寸:(200, 150)
缩略图尺寸:(200, 150)
缩小一半后尺寸:(200, 150)
✓ 已保存缩放后的图片
2. 旋转图片
# 示例 8:旋转图片
from PIL import Image, ImageDraw
# 创建带标记的测试图片(方便观察旋转效果)
img = Image.new('RGB', (200, 200), color='white')
draw = ImageDraw.Draw(img)
# 绘制一个箭头标记
draw.polygon([(100, 50), (150, 100), (120, 100), (120, 150), (80, 150), (80, 100), (50, 100)], fill='red')
# 旋转 90 度
img_rotated_90 = img.rotate(90, expand=True)
print(f"旋转90度后尺寸:{img_rotated_90.size}")
# 旋转 45 度
img_rotated_45 = img.rotate(45, expand=True)
print(f"旋转45度后尺寸:{img_rotated_45.size}")
# 旋转 180 度
img_rotated_180 = img.rotate(180, expand=True)
# 保存
img.save('original_arrow.png')
img_rotated_90.save('rotated_90.png')
img_rotated_45.save('rotated_45.png')
img_rotated_180.save('rotated_180.png')
print("✓ 已保存旋转后的图片")
3. 翻转图片
# 示例 9:翻转图片
from PIL import Image, ImageDraw
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightblue')
draw = ImageDraw.Draw(img)
draw.text((50, 50), "ABC", fill='black')
# 水平翻转(左右镜像)
img_flip_h = img.transpose(Image.FLIP_LEFT_RIGHT)
# 垂直翻转(上下镜像)
img_flip_v = img.transpose(Image.FLIP_TOP_BOTTOM)
# 旋转 90 度(顺时针)
img_rotate_90 = img.transpose(Image.ROTATE_90)
# 旋转 180 度
img_rotate_180 = img.transpose(Image.ROTATE_180)
# 旋转 270 度(逆时针 90 度)
img_rotate_270 = img.transpose(Image.ROTATE_270)
print("✓ 已创建翻转和旋转的图片")
img.save('original.png')
img_flip_h.save('flip_horizontal.png')
img_flip_v.save('flip_vertical.png')
4. 裁剪图片
# 示例 10:裁剪图片
from PIL import Image
# 创建测试图片
img = Image.new('RGB', (400, 300), color='lightgreen')
# 定义裁剪区域 (left, top, right, bottom)
box = (100, 50, 300, 250)
img_cropped = img.crop(box)
print(f"原始尺寸:{img.size}")
print(f"裁剪后尺寸:{img_cropped.size}")
print(f"裁剪区域:{box}")
# 保存
img.save('original_crop.png')
img_cropped.save('cropped.png')
print("✓ 已保存裁剪后的图片")
运行结果:
原始尺寸:(400, 300)
裁剪后尺寸:(200, 200)
裁剪区域:(100, 50, 300, 250)
✓ 已保存裁剪后的图片
5. 粘贴图片
# 示例 11:粘贴图片
from PIL import Image
# 创建背景图片
background = Image.new('RGB', (400, 300), color='lightblue')
# 创建要粘贴的图片
foreground = Image.new('RGB', (100, 100), color='red')
# 粘贴到指定位置
background.paste(foreground, (50, 50))
# 粘贴多个
foreground2 = Image.new('RGB', (80, 80), color='green')
background.paste(foreground2, (200, 100))
# 粘贴时使用遮罩(只粘贴不透明部分)
foreground_rgba = Image.new('RGBA', (100, 100), color=(255, 0, 0, 128)) # 半透明红色
background.paste(foreground_rgba, (150, 150), foreground_rgba) # 第三个参数是遮罩
background.save('pasted.png')
print("✓ 已保存粘贴后的图片")
第四部分:图片绘制
1. 基本绘制
# 示例 12:基本绘制
from PIL import Image, ImageDraw
# 创建图片
img = Image.new('RGB', (400, 300), color='white')
draw = ImageDraw.Draw(img)
# 绘制矩形
draw.rectangle([50, 50, 150, 150], fill='red', outline='black', width=2)
# 绘制椭圆/圆形
draw.ellipse([200, 50, 300, 150], fill='blue', outline='black', width=2)
# 绘制直线
draw.line([50, 200, 350, 200], fill='green', width=3)
# 绘制多边形
draw.polygon([(100, 250), (150, 220), (200, 250), (150, 280)], fill='yellow', outline='black')
# 绘制点
for i in range(10):
draw.ellipse([300 + i*5, 250, 305 + i*5, 255], fill='purple')
img.save('drawing_basic.png')
print("✓ 已保存基本绘制图片")
2. 绘制文本
# 示例 13:绘制文本
from PIL import Image, ImageDraw, ImageFont
import os
# 创建图片
img = Image.new('RGB', (400, 200), color='white')
draw = ImageDraw.Draw(img)
# 使用默认字体绘制文本
draw.text((10, 10), "Hello, Pillow!", fill='black')
# 指定字体大小(如果系统有字体)
try:
# Windows 字体路径
font_path = "C:/Windows/Fonts/arial.ttf"
if os.path.exists(font_path):
font = ImageFont.truetype(font_path, size=30)
draw.text((10, 50), "Custom Font", fill='blue', font=font)
else:
# 使用默认字体
font = ImageFont.load_default()
draw.text((10, 50), "Default Font", fill='blue', font=font)
except:
# 如果字体加载失败,使用默认字体
font = ImageFont.load_default()
draw.text((10, 50), "Default Font", fill='blue', font=font)
# 获取文本尺寸
text = "Text Size"
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
print(f"文本 '{text}' 的尺寸:{text_width} x {text_height}")
# 居中文本
img_center = Image.new('RGB', (300, 100), color='lightgray')
draw_center = ImageDraw.Draw(img_center)
text = "Centered"
bbox = draw_center.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x = (300 - text_width) // 2
y = (100 - text_height) // 2
draw_center.text((x, y), text, fill='black', font=font)
img.save('text_drawing.png')
img_center.save('text_centered.png')
print("✓ 已保存文本绘制图片")
3. 高级绘制
# 示例 14:高级绘制
from PIL import Image, ImageDraw
import math
# 创建图片
img = Image.new('RGB', (400, 400), color='white')
draw = ImageDraw.Draw(img)
# 绘制弧形
draw.arc([50, 50, 150, 150], start=0, end=180, fill='red', width=3)
# 绘制弦(填充的弧形)
draw.chord([200, 50, 300, 150], start=0, end=270, fill='blue', outline='black')
# 绘制饼图
draw.pieslice([50, 200, 150, 300], start=0, end=90, fill='green', outline='black')
# 绘制圆角矩形(通过绘制多个形状模拟)
def draw_rounded_rectangle(draw, bbox, radius, fill=None, outline=None, width=1):
"""绘制圆角矩形"""
left, top, right, bottom = bbox
# 绘制矩形主体
draw.rectangle([left + radius, top, right - radius, bottom], fill=fill, outline=outline, width=width)
draw.rectangle([left, top + radius, right, bottom - radius], fill=fill, outline=outline, width=width)
# 绘制四个角
draw.ellipse([left, top, left + 2*radius, top + 2*radius], fill=fill, outline=outline, width=width)
draw.ellipse([right - 2*radius, top, right, top + 2*radius], fill=fill, outline=outline, width=width)
draw.ellipse([left, bottom - 2*radius, left + 2*radius, bottom], fill=fill, outline=outline, width=width)
draw.ellipse([right - 2*radius, bottom - 2*radius, right, bottom], fill=fill, outline=outline, width=width)
draw_rounded_rectangle(draw, [200, 200, 350, 350], radius=20, fill='yellow', outline='black', width=2)
img.save('drawing_advanced.png')
print("✓ 已保存高级绘制图片")
第五部分:图片滤镜和增强
1. 内置滤镜
# 示例 15:内置滤镜
from PIL import Image, ImageFilter
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightblue')
# 应用模糊滤镜
img_blur = img.filter(ImageFilter.BLUR)
# 应用轮廓滤镜
img_contour = img.filter(ImageFilter.CONTOUR)
# 应用细节增强
img_detail = img.filter(ImageFilter.DETAIL)
# 应用边缘增强
img_edge = img.filter(ImageFilter.EDGE_ENHANCE)
# 应用更强的边缘增强
img_edge_more = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
# 应用浮雕效果
img_emboss = img.filter(ImageFilter.EMBOSS)
# 应用查找边缘
img_find_edges = img.filter(ImageFilter.FIND_EDGES)
# 应用平滑
img_smooth = img.filter(ImageFilter.SMOOTH)
# 应用更强的平滑
img_smooth_more = img.filter(ImageFilter.SMOOTH_MORE)
# 应用锐化
img_sharpen = img.filter(ImageFilter.SHARPEN)
print("✓ 已应用各种滤镜")
# 注意:实际使用时需要加载真实图片才能看到滤镜效果
2. 高斯模糊
# 示例 16:高斯模糊
from PIL import Image, ImageFilter
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightblue')
# 应用高斯模糊(可以指定半径)
img_gaussian = img.filter(ImageFilter.GaussianBlur(radius=5))
img_gaussian_strong = img.filter(ImageFilter.GaussianBlur(radius=10))
print("✓ 已应用高斯模糊")
3. 图片增强
# 示例 17:图片增强
from PIL import Image, ImageEnhance
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightblue')
# 亮度增强
enhancer_brightness = ImageEnhance.Brightness(img)
img_bright = enhancer_brightness.enhance(1.5) # 1.5倍亮度
img_dark = enhancer_brightness.enhance(0.5) # 0.5倍亮度
# 对比度增强
enhancer_contrast = ImageEnhance.Contrast(img)
img_high_contrast = enhancer_contrast.enhance(2.0) # 2倍对比度
img_low_contrast = enhancer_contrast.enhance(0.5) # 0.5倍对比度
# 色彩饱和度增强
enhancer_color = ImageEnhance.Color(img)
img_vivid = enhancer_color.enhance(2.0) # 2倍饱和度
img_desaturated = enhancer_color.enhance(0.5) # 0.5倍饱和度
# 锐度增强
enhancer_sharpness = ImageEnhance.Sharpness(img)
img_sharp = enhancer_sharpness.enhance(2.0) # 2倍锐度
img_soft = enhancer_sharpness.enhance(0.5) # 0.5倍锐度
print("✓ 已应用各种增强效果")
第六部分:图片合成和混合
1. 图片混合
# 示例 18:图片混合
from PIL import Image, ImageDraw
# 创建两个图片
img1 = Image.new('RGB', (200, 200), color='red')
img2 = Image.new('RGB', (200, 200), color='blue')
# 使用 blend 混合(alpha 值 0-1)
img_blended = Image.blend(img1, img2, alpha=0.5) # 50%混合
# 使用 composite 合成(需要 RGBA 模式)
img1_rgba = Image.new('RGBA', (200, 200), color=(255, 0, 0, 128)) # 半透明红色
img2_rgba = Image.new('RGBA', (200, 200), color=(0, 0, 255, 128)) # 半透明蓝色
img_composite = Image.alpha_composite(img1_rgba, img2_rgba)
print("✓ 已创建混合图片")
img_blended.save('blended.png')
img_composite.save('composite.png')
2. 创建水印
# 示例 19:创建水印
from PIL import Image, ImageDraw, ImageFont
import os
# 创建主图片
main_img = Image.new('RGB', (400, 300), color='lightblue')
# 创建水印图片
watermark = Image.new('RGBA', (200, 100), color=(0, 0, 0, 0)) # 透明背景
draw = ImageDraw.Draw(watermark)
draw.text((10, 10), "WATERMARK", fill=(255, 255, 255, 128)) # 半透明白色文字
# 将水印粘贴到主图片
main_img.paste(watermark, (100, 100), watermark) # 第三个参数是遮罩
main_img.save('watermarked.png')
print("✓ 已创建带水印的图片")
第七部分:图片信息和处理
1. 获取图片信息
# 示例 20:获取图片信息
from PIL import Image
import os
# 创建测试图片
img = Image.new('RGB', (400, 300), color='lightblue')
img.save('info_test.jpg')
# 打开图片
img = Image.open('info_test.jpg')
# 基本信息
print(f"格式:{img.format}")
print(f"模式:{img.mode}")
print(f"尺寸:{img.size}")
print(f"宽度:{img.width}")
print(f"高度:{img.height}")
# 获取图片信息字典
info = img.info
print(f"图片信息:{info}")
# 检查是否有透明通道
has_alpha = img.mode in ('RGBA', 'LA') or 'transparency' in img.info
print(f"是否有透明通道:{has_alpha}")
# 获取调色板(如果是调色板模式)
if img.mode == 'P':
palette = img.getpalette()
print(f"调色板:{palette}")
2. 图片格式转换
# 示例 21:图片格式转换
from PIL import Image
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightgreen')
# 保存为不同格式
formats = {
'JPEG': 'jpg',
'PNG': 'png',
'BMP': 'bmp',
'GIF': 'gif',
'TIFF': 'tiff'
}
for format_name, ext in formats.items():
try:
filename = f'converted.{ext}'
img.save(filename, format=format_name)
print(f"✓ 已保存为 {format_name} 格式:{filename}")
except Exception as e:
print(f"✗ 无法保存为 {format_name} 格式:{e}")
3. 批量处理图片
# 示例 22:批量处理图片
from PIL import Image
import os
import glob
def batch_resize_images(input_dir, output_dir, size=(800, 600)):
"""批量调整图片大小"""
os.makedirs(output_dir, exist_ok=True)
# 获取所有图片文件
image_extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.gif']
image_files = []
for ext in image_extensions:
image_files.extend(glob.glob(os.path.join(input_dir, ext)))
image_files.extend(glob.glob(os.path.join(input_dir, ext.upper())))
processed = 0
for img_path in image_files:
try:
# 打开图片
img = Image.open(img_path)
# 调整大小
img_resized = img.resize(size, Image.Resampling.LANCZOS)
# 保存
filename = os.path.basename(img_path)
output_path = os.path.join(output_dir, filename)
img_resized.save(output_path)
processed += 1
print(f"✓ 已处理:{filename}")
except Exception as e:
print(f"✗ 处理失败 {img_path}:{e}")
print(f"\n总共处理了 {processed} 张图片")
# 使用示例(需要先创建测试图片)
# batch_resize_images('input_images', 'output_images', size=(800, 600))
print("批量处理函数已定义,可以调用 batch_resize_images() 使用")
第八部分:实际应用示例
1. 创建缩略图
# 示例 23:创建缩略图
from PIL import Image
import os
def create_thumbnail(input_path, output_path, size=(128, 128)):
"""创建缩略图"""
try:
img = Image.open(input_path)
img.thumbnail(size, Image.Resampling.LANCZOS)
img.save(output_path)
print(f"✓ 已创建缩略图:{output_path}")
return True
except Exception as e:
print(f"✗ 创建缩略图失败:{e}")
return False
# 创建测试图片
test_img = Image.new('RGB', (800, 600), color='lightblue')
test_img.save('original_large.jpg')
# 创建缩略图
create_thumbnail('original_large.jpg', 'thumbnail.jpg', size=(128, 128))
2. 图片拼接
# 示例 24:图片拼接
from PIL import Image
def concatenate_images_horizontal(images, output_path):
"""水平拼接图片"""
widths, heights = zip(*(img.size for img in images))
total_width = sum(widths)
max_height = max(heights)
new_img = Image.new('RGB', (total_width, max_height))
x_offset = 0
for img in images:
new_img.paste(img, (x_offset, 0))
x_offset += img.size[0]
new_img.save(output_path)
print(f"✓ 已保存拼接图片:{output_path}")
def concatenate_images_vertical(images, output_path):
"""垂直拼接图片"""
widths, heights = zip(*(img.size for img in images))
max_width = max(widths)
total_height = sum(heights)
new_img = Image.new('RGB', (max_width, total_height))
y_offset = 0
for img in images:
new_img.paste(img, (0, y_offset))
y_offset += img.size[1]
new_img.save(output_path)
print(f"✓ 已保存拼接图片:{output_path}")
# 创建测试图片
img1 = Image.new('RGB', (100, 100), color='red')
img2 = Image.new('RGB', (100, 100), color='green')
img3 = Image.new('RGB', (100, 100), color='blue')
# 水平拼接
concatenate_images_horizontal([img1, img2, img3], 'concatenated_horizontal.jpg')
# 垂直拼接
concatenate_images_vertical([img1, img2, img3], 'concatenated_vertical.jpg')
3. 图片压缩
# 示例 25:图片压缩
from PIL import Image
import os
def compress_image(input_path, output_path, quality=85, max_size=None):
"""压缩图片"""
try:
img = Image.open(input_path)
# 如果指定了最大尺寸,先调整大小
if max_size:
img.thumbnail(max_size, Image.Resampling.LANCZOS)
# 转换为 RGB(如果是 RGBA)
if img.mode == 'RGBA':
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3]) # 使用 alpha 通道作为遮罩
img = background
elif img.mode != 'RGB':
img = img.convert('RGB')
# 保存为 JPEG
img.save(output_path, 'JPEG', quality=quality, optimize=True)
# 获取文件大小
original_size = os.path.getsize(input_path)
compressed_size = os.path.getsize(output_path)
compression_ratio = (1 - compressed_size / original_size) * 100
print(f"✓ 压缩完成:{output_path}")
print(f" 原始大小:{original_size / 1024:.2f} KB")
print(f" 压缩后大小:{compressed_size / 1024:.2f} KB")
print(f" 压缩率:{compression_ratio:.2f}%")
return True
except Exception as e:
print(f"✗ 压缩失败:{e}")
return False
# 创建测试图片
test_img = Image.new('RGB', (2000, 1500), color='lightblue')
test_img.save('large_image.jpg', quality=100)
# 压缩图片
compress_image('large_image.jpg', 'compressed_image.jpg', quality=60)
4. 添加边框
# 示例 26:添加边框
from PIL import Image, ImageDraw
def add_border(img, border_width=10, border_color='black'):
"""给图片添加边框"""
width, height = img.size
new_width = width + 2 * border_width
new_height = height + 2 * border_width
# 创建新图片
bordered_img = Image.new(img.mode, (new_width, new_height), border_color)
# 粘贴原图片
bordered_img.paste(img, (border_width, border_width))
return bordered_img
# 创建测试图片
img = Image.new('RGB', (200, 200), color='lightblue')
# 添加边框
img_bordered = add_border(img, border_width=20, border_color='red')
img_bordered.save('bordered.png')
print("✓ 已保存带边框的图片")
5. 创建九宫格图片
# 示例 27:创建九宫格图片
from PIL import Image
def create_nine_grid(img, grid_size=3):
"""将图片分割成九宫格"""
width, height = img.size
cell_width = width // grid_size
cell_height = height // grid_size
images = []
for row in range(grid_size):
for col in range(grid_size):
left = col * cell_width
top = row * cell_height
right = left + cell_width
bottom = top + cell_height
cell = img.crop((left, top, right, bottom))
images.append(cell)
return images
# 创建测试图片
img = Image.new('RGB', (300, 300), color='lightblue')
# 分割成九宫格
cells = create_nine_grid(img, grid_size=3)
# 保存每个格子
for i, cell in enumerate(cells):
cell.save(f'grid_cell_{i+1}.png')
print("✓ 已创建九宫格图片")
第九部分:高级功能
1. 图片动画(GIF)
# 示例 28:创建 GIF 动画
from PIL import Image, ImageDraw
def create_animated_gif(output_path, frames, duration=100):
"""创建 GIF 动画"""
frames[0].save(
output_path,
save_all=True,
append_images=frames[1:],
duration=duration,
loop=0
)
print(f"✓ 已创建 GIF 动画:{output_path}")
# 创建动画帧
frames = []
for i in range(10):
img = Image.new('RGB', (200, 200), color='white')
draw = ImageDraw.Draw(img)
# 绘制一个移动的圆
x = 50 + i * 10
y = 100
draw.ellipse([x-20, y-20, x+20, y+20], fill='red')
frames.append(img)
# 创建 GIF
create_animated_gif('animation.gif', frames, duration=100)
2. EXIF 信息处理
# 示例 29:处理 EXIF 信息
from PIL import Image
from PIL.ExifTags import TAGS
def get_exif_data(img_path):
"""获取图片的 EXIF 信息"""
try:
img = Image.open(img_path)
exif_data = img._getexif()
if exif_data:
exif_dict = {}
for tag_id, value in exif_data.items():
tag = TAGS.get(tag_id, tag_id)
exif_dict[tag] = value
return exif_dict
else:
return None
except Exception as e:
print(f"获取 EXIF 信息失败:{e}")
return None
# 注意:只有某些图片格式(如 JPEG)才包含 EXIF 信息
print("EXIF 信息处理函数已定义")
print("使用 get_exif_data('image.jpg') 获取 EXIF 信息")
3. 图片验证
# 示例 30:图片验证
from PIL import Image
import os
def validate_image(file_path):
"""验证图片文件是否有效"""
try:
# 尝试打开图片
img = Image.open(file_path)
# 验证图片
img.verify()
# 重新打开(verify 后需要重新打开)
img = Image.open(file_path)
return True, f"✓ 图片有效:{img.format}, {img.size}, {img.mode}"
except Exception as e:
return False, f"✗ 图片无效:{e}"
# 创建测试图片
test_img = Image.new('RGB', (100, 100), color='lightblue')
test_img.save('valid_image.jpg')
# 验证图片
is_valid, message = validate_image('valid_image.jpg')
print(message)
第十部分:性能优化和最佳实践
1. 内存优化
# 示例 31:内存优化
from PIL import Image
def process_large_image_optimized(input_path, output_path):
"""优化处理大图片"""
# 方法1:使用 thumbnail 而不是 resize(自动优化)
img = Image.open(input_path)
img.thumbnail((800, 600), Image.Resampling.LANCZOS)
img.save(output_path)
# 方法2:分块处理(对于超大图片)
# 使用 Image.tile 或分块读取
print("✓ 已优化处理大图片")
print("内存优化函数已定义")
2. 批量处理最佳实践
# 示例 32:批量处理最佳实践
from PIL import Image
import os
import glob
def batch_process_images(input_dir, output_dir, process_func):
"""批量处理图片的通用函数"""
os.makedirs(output_dir, exist_ok=True)
# 支持的图片格式
extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.gif', '*.tiff']
image_files = []
for ext in extensions:
image_files.extend(glob.glob(os.path.join(input_dir, ext)))
image_files.extend(glob.glob(os.path.join(input_dir, ext.upper())))
success_count = 0
fail_count = 0
for img_path in image_files:
try:
# 处理图片
img = Image.open(img_path)
processed_img = process_func(img)
# 保存
filename = os.path.basename(img_path)
name, ext = os.path.splitext(filename)
output_path = os.path.join(output_dir, f"{name}_processed{ext}")
processed_img.save(output_path)
success_count += 1
except Exception as e:
print(f"✗ 处理失败 {img_path}:{e}")
fail_count += 1
print(f"\n处理完成:成功 {success_count},失败 {fail_count}")
# 定义处理函数
def resize_to_800(img):
"""调整大小到800px宽度"""
ratio = 800 / img.width
new_height = int(img.height * ratio)
return img.resize((800, new_height), Image.Resampling.LANCZOS)
# 使用示例
# batch_process_images('input', 'output', resize_to_800)
print("批量处理函数已定义")
第十一部分:常见问题和解决方案
1. 常见错误处理
# 示例 33:常见错误处理
from PIL import Image
import os
def safe_open_image(file_path):
"""安全地打开图片"""
try:
if not os.path.exists(file_path):
raise FileNotFoundError(f"文件不存在:{file_path}")
img = Image.open(file_path)
# 验证图片
img.verify()
# 重新打开(verify 后需要重新打开)
img = Image.open(file_path)
return img, None
except FileNotFoundError as e:
return None, str(e)
except Image.UnidentifiedImageError:
return None, "无法识别的图片格式"
except Exception as e:
return None, f"打开图片失败:{str(e)}"
# 测试
img, error = safe_open_image('nonexistent.jpg')
if error:
print(f"错误:{error}")
else:
print("✓ 图片打开成功")
2. 格式兼容性
# 示例 34:格式兼容性处理
from PIL import Image
def convert_to_compatible_format(img, target_format='JPEG'):
"""转换为兼容格式"""
# 如果目标格式是 JPEG,需要转换为 RGB
if target_format == 'JPEG':
if img.mode == 'RGBA':
# 创建白色背景
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
return background
elif img.mode != 'RGB':
return img.convert('RGB')
return img
# 创建 RGBA 图片
img_rgba = Image.new('RGBA', (100, 100), color=(255, 0, 0, 128))
# 转换为 JPEG 兼容格式
img_rgb = convert_to_compatible_format(img_rgba, 'JPEG')
img_rgb.save('converted.jpg', 'JPEG')
print("✓ 已转换为兼容格式")
第十二部分:综合示例
1. 图片处理工具类
# 示例 35:图片处理工具类
from PIL import Image, ImageFilter, ImageEnhance, ImageDraw, ImageFont
import os
class ImageProcessor:
"""图片处理工具类"""
def __init__(self, image_path):
self.image = Image.open(image_path)
self.original = self.image.copy()
def reset(self):
"""重置为原始图片"""
self.image = self.original.copy()
def resize(self, size, keep_ratio=False):
"""调整大小"""
if keep_ratio:
self.image.thumbnail(size, Image.Resampling.LANCZOS)
else:
self.image = self.image.resize(size, Image.Resampling.LANCZOS)
return self
def rotate(self, angle):
"""旋转"""
self.image = self.image.rotate(angle, expand=True)
return self
def apply_filter(self, filter_name):
"""应用滤镜"""
filters = {
'blur': ImageFilter.BLUR,
'contour': ImageFilter.CONTOUR,
'emboss': ImageFilter.EMBOSS,
'sharpen': ImageFilter.SHARPEN,
'smooth': ImageFilter.SMOOTH,
'edge': ImageFilter.EDGE_ENHANCE
}
if filter_name in filters:
self.image = self.image.filter(filters[filter_name])
return self
def enhance(self, brightness=1.0, contrast=1.0, saturation=1.0):
"""增强"""
if brightness != 1.0:
enhancer = ImageEnhance.Brightness(self.image)
self.image = enhancer.enhance(brightness)
if contrast != 1.0:
enhancer = ImageEnhance.Contrast(self.image)
self.image = enhancer.enhance(contrast)
if saturation != 1.0:
enhancer = ImageEnhance.Color(self.image)
self.image = enhancer.enhance(saturation)
return self
def add_text(self, text, position=(10, 10), color='black', size=20):
"""添加文字"""
draw = ImageDraw.Draw(self.image)
try:
font = ImageFont.truetype("arial.ttf", size)
except:
font = ImageFont.load_default()
draw.text(position, text, fill=color, font=font)
return self
def save(self, output_path, **kwargs):
"""保存"""
self.image.save(output_path, **kwargs)
print(f"✓ 已保存:{output_path}")
return self
def show(self):
"""显示"""
self.image.show()
return self
# 使用示例
# 创建测试图片
test_img = Image.new('RGB', (400, 300), color='lightblue')
test_img.save('test_processor.jpg')
# 使用工具类
processor = ImageProcessor('test_processor.jpg')
processor.resize((200, 150))\
.enhance(brightness=1.2, contrast=1.1)\
.apply_filter('sharpen')\
.add_text('Processed', position=(10, 10))\
.save('processed_result.jpg')
print("✓ 图片处理工具类示例完成")
总结
核心概念回顾
- Image 对象:Pillow 的核心,代表一张图片
- 图片模式:RGB、RGBA、L(灰度)等
- 基本操作:打开、保存、转换
- 图片变换:缩放、旋转、裁剪、翻转
- 图片绘制:使用 ImageDraw 绘制图形和文字
- 滤镜和增强:使用 ImageFilter 和 ImageEnhance
- 图片合成:混合、粘贴、合成
常用方法总结
Image.open():打开图片Image.new():创建新图片img.save():保存图片img.resize():调整大小img.rotate():旋转img.crop():裁剪img.paste():粘贴img.filter():应用滤镜ImageDraw.Draw():创建绘制对象
最佳实践
- 内存管理:处理大图片时使用 thumbnail 而不是 resize
- 格式转换:保存 JPEG 前确保转换为 RGB 模式
- 错误处理:使用 try-except 处理图片操作
- 批量处理:使用循环和函数批量处理多张图片
- 性能优化:对于大图片,考虑分块处理
下一步学习建议
- 学习更多高级滤镜和效果
- 结合 NumPy 进行像素级操作
- 学习图像识别和处理算法
- 实践真实项目,处理实际图片
- 阅读 Pillow 官方文档