行莫
行莫
发布于 2025-11-18 / 8 阅读
0
0

Pillow 图像处理详解:从入门到精通

Pillow 图像处理详解:从入门到精通

引言

Pillow(PIL - Python Imaging Library)是 Python 中最强大的图像处理库之一。它提供了丰富的图像操作功能,包括图像打开、保存、缩放、旋转、滤镜、绘制等,是进行图像处理的必备工具。

本教程特点:

  • 每个概念都配有可直接运行的代码示例
  • 代码可以直接复制到 Python 解释器中执行
  • 循序渐进,从基础到高级
  • 包含实际应用场景和最佳实践

学习建议:

  1. 阅读每个示例代码
  2. 复制代码到 Python 解释器或 Jupyter Notebook 中运行
  3. 尝试修改代码,观察结果变化
  4. 准备一些测试图片用于实践

安装 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("✓ 图片处理工具类示例完成")

总结

核心概念回顾

  1. Image 对象:Pillow 的核心,代表一张图片
  2. 图片模式:RGB、RGBA、L(灰度)等
  3. 基本操作:打开、保存、转换
  4. 图片变换:缩放、旋转、裁剪、翻转
  5. 图片绘制:使用 ImageDraw 绘制图形和文字
  6. 滤镜和增强:使用 ImageFilter 和 ImageEnhance
  7. 图片合成:混合、粘贴、合成

常用方法总结

  • Image.open():打开图片
  • Image.new():创建新图片
  • img.save():保存图片
  • img.resize():调整大小
  • img.rotate():旋转
  • img.crop():裁剪
  • img.paste():粘贴
  • img.filter():应用滤镜
  • ImageDraw.Draw():创建绘制对象

最佳实践

  1. 内存管理:处理大图片时使用 thumbnail 而不是 resize
  2. 格式转换:保存 JPEG 前确保转换为 RGB 模式
  3. 错误处理:使用 try-except 处理图片操作
  4. 批量处理:使用循环和函数批量处理多张图片
  5. 性能优化:对于大图片,考虑分块处理

下一步学习建议

  1. 学习更多高级滤镜和效果
  2. 结合 NumPy 进行像素级操作
  3. 学习图像识别和处理算法
  4. 实践真实项目,处理实际图片
  5. 阅读 Pillow 官方文档

评论