—— Pillow:Python 图像处理的瑞士军刀
from PIL import Image
# 打开图片
img = Image.open("photo.jpg")
print(f"尺寸: {img.size}") # (宽, 高)
print(f"格式: {img.format}") # JPEG
print(f"模式: {img.mode}") # RGB
# 保存为其他格式
img.save("photo.png") # JPEG → PNG
img.save("photo.webp", quality=85) # WebP 压缩
# 缩放图片
# resize() 返回新图片,不修改原图
img_resized = img.resize((800, 600), Image.LANCZOS)
img_resized.save("photo_800x600.jpg")
# thumbnail() 原地缩放(不超限)
img_thumb = img.copy()
img_thumb.thumbnail((200, 200)) # 等比缩放到 200x200 内
img_thumb.save("thumbnail.jpg")
# 裁剪图片 (left, upper, right, lower)
cropped = img.crop((100, 50, 500, 400))
cropped.save("cropped.jpg")
# 旋转图片
rotated = img.rotate(90) # 逆时针 90 度
rotated = img.rotate(45, expand=True) # 扩展画布容纳旋转
# 翻转
flipped_h = img.transpose(Image.FLIP_LEFT_RIGHT)
flipped_v = img.transpose(Image.FLIP_TOP_BOTTOM)
from PIL import Image, ImageFilter
img = Image.open("photo.jpg")
# 高斯模糊
blurred = img.filter(ImageFilter.GaussianBlur(radius=5))
# 盒模糊(更快)
box_blurred = img.filter(ImageFilter.BoxBlur(radius=3))
# 锐化
sharpened = img.filter(ImageFilter.SHARPEN)
# 边缘检测
edges = img.filter(ImageFilter.FIND_EDGES)
# 浮雕效果
embossed = img.filter(ImageFilter.EMBOSS)
# 轮廓提取
contoured = img.filter(ImageFilter.CONTOUR)
# 自定义卷积核
# 3x3 锐化核
kernel = ImageFilter.Kernel(
size=(3, 3),
kernel=[0, -1, 0,
-1, 5, -1,
0, -1, 0],
scale=1,
offset=0
)
custom_sharp = img.filter(kernel)
# USM 锐化(Unsharp Mask)
usm = img.filter(ImageFilter.UnsharpMask(
radius=2, percent=150, threshold=3
))
from PIL import Image, ImageDraw, ImageFont
# 创建空白画布
canvas = Image.new("RGB", (800, 600), "#1a1a2e")
draw = ImageDraw.Draw(canvas)
# 绘制矩形
draw.rectangle([50, 50, 200, 150], fill="#34d399", outline="#ffffff", width=2)
# 绘制圆形
draw.ellipse([300, 50, 450, 200], fill="#7dd3fc")
# 绘制线条
draw.line([50, 300, 750, 300], fill="#fbbf24", width=3)
# 绘制文字
draw.text((100, 400), "Hello Pillow!", fill="#ffffff")
# 使用 TrueType 字体
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 36)
draw.text((100, 450), "Big Bold Text", fill="#34d399", font=font)
except:
draw.text((100, 450), "Big Bold Text", fill="#34d399")
canvas.save("drawing.png")
# 图片水印
def add_watermark(image_path, text, output_path, opacity=128):
"""给图片添加文字水印"""
img = Image.open(image_path).convert("RGBA")
watermark = Image.new("RGBA", img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)
try:
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 40)
except:
font = ImageFont.load_default()
# 多行对角水印
for y in range(0, img.height, 150):
for x in range(0, img.width, 300):
draw.text((x, y), text, fill=(255, 255, 255, opacity), font=font)
result = Image.alpha_composite(img, watermark)
result.convert("RGB").save(output_path)
from PIL import Image, ImageEnhance
img = Image.open("photo.jpg")
# 调整亮度
enhancer = ImageEnhance.Brightness(img)
brighter = enhancer.enhance(1.5) # 1.5倍亮度
darker = enhancer.enhance(0.5) # 0.5倍亮度
# 调整对比度
enhancer = ImageEnhance.Contrast(img)
high_contrast = enhancer.enhance(2.0)
# 调整饱和度
enhancer = ImageEnhance.Color(img)
vivid = enhancer.enhance(1.5)
grayscale = enhancer.enhance(0.0) # 完全去色
# 调整锐度
enhancer = ImageEnhance.Sharpness(img)
sharper = enhancer.enhance(2.0)
# 灰度转换
gray = img.convert("L") # 8位灰度
# 通道分离
r, g, b = img.split()
# 只保留红色通道
red_only = Image.merge("RGB", (r, g.point(lambda x: 0), b.point(lambda x: 0)))
import os
from pathlib import Path
from PIL import Image
def batch_resize(input_dir, output_dir, size=(800, 600)):
"""批量缩放图片"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
stats = {"success": 0, "failed": 0}
for f in input_path.iterdir():
if f.suffix.lower() not in (".jpg", ".jpeg", ".png", ".webp"):
continue
try:
img = Image.open(f)
img_resized = img.resize(size, Image.LANCZOS)
img_resized.save(output_path / f.name, quality=90)
stats["success"] += 1
print(f" ✅ {f.name}: {img.size} → {img_resized.size}")
except Exception as e:
stats["failed"] += 1
print(f" ❌ {f.name}: {e}")
print(f"\\n批量缩放完成: 成功{stats['success']} 失败{stats['failed']}")
def batch_convert(input_dir, output_dir, target_format="WEBP"):
"""批量格式转换"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
for f in input_path.iterdir():
if f.suffix.lower() not in (".jpg", ".jpeg", ".png"):
continue
try:
img = Image.open(f)
out_name = f.stem + ".webp"
img.save(output_path / out_name, target_format, quality=85)
original_size = f.stat().st_size
new_size = (output_path / out_name).stat().st_size
saved = (1 - new_size / original_size) * 100
print(f" ✅ {f.name} → {out_name} (节省{saved:.1f}%)")
except Exception as e:
print(f" ❌ {f.name}: {e}")
def batch_watermark(input_dir, output_dir, text="COPYRIGHT"):
"""批量添加水印"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
for f in input_path.iterdir():
if f.suffix.lower() not in (".jpg", ".jpeg", ".png"):
continue
try:
add_watermark(str(f), text, str(output_path / f.name))
print(f" ✅ {f.name} 水印已添加")
except Exception as e:
print(f" ❌ {f.name}: {e}")
#!/usr/bin/env python3
"""第21课 图像处理验证"""
from PIL import Image, ImageDraw, ImageFilter, ImageEnhance
import tempfile
import os
def test_basic_operations():
"""基础操作测试"""
with tempfile.TemporaryDirectory() as tmpdir:
# 创建测试图片
img = Image.new("RGB", (400, 300), "#ff0000")
img.save(os.path.join(tmpdir, "test.jpg"))
# 打开验证
opened = Image.open(os.path.join(tmpdir, "test.jpg"))
assert opened.size == (400, 300)
# 缩放
resized = opened.resize((200, 150), Image.LANCZOS)
assert resized.size == (200, 150)
# 裁剪
cropped = opened.crop((50, 50, 150, 100))
assert cropped.size == (100, 50)
# 旋转
rotated = opened.rotate(90)
assert rotated.size == (400, 300) # 默认不扩展
print("✅ 基础操作测试通过")
def test_filters():
"""滤镜测试"""
img = Image.new("RGB", (100, 100), "#ff0000")
blurred = img.filter(ImageFilter.GaussianBlur(radius=2))
assert blurred.size == (100, 100)
sharpened = img.filter(ImageFilter.SHARPEN)
assert sharpened.size == (100, 100)
edges = img.filter(ImageFilter.FIND_EDGES)
assert edges.size == (100, 100)
print("✅ 滤镜测试通过")
def test_draw():
"""绘图测试"""
img = Image.new("RGB", (200, 200), "#1a1a2e")
draw = ImageDraw.Draw(img)
draw.rectangle([10, 10, 100, 100], fill="#34d399")
draw.ellipse([50, 50, 150, 150], fill="#7dd3fc")
draw.text((10, 160), "Test", fill="#ffffff")
# 验证绘制确实改变了像素
pixel = img.getpixel((50, 50)) # 矩形区域内
assert pixel != (26, 26, 46) # 不是背景色
print("✅ 绘图测试通过")
def test_enhance():
"""增强操作测试"""
img = Image.new("RGB", (100, 100), "#ff0000")
brighter = ImageEnhance.Brightness(img).enhance(1.5)
assert brighter.size == (100, 100)
gray = img.convert("L")
assert gray.mode == "L"
r, g, b = img.split()
assert r.size == (100, 100)
print("✅ 增强操作测试通过")
if __name__ == "__main__":
test_basic_operations()
test_filters()
test_draw()
test_enhance()
print("\n🎉 第21课全部验证通过!")