如何使用Python批量裁剪图片?3种场景,代码直接拿去用
·
为什么要批量裁剪图片?
做电商要统一主图尺寸、社交媒体头像要裁成正方形、证件照需要固定比例……手动一张张裁,几十张就够你喝两杯咖啡了。
用Python + Pillow,几行代码就能批量搞定。这篇博客覆盖最常用的3个场景,每个都给可运行代码。
场景一:固定尺寸裁剪(左上角裁剪)
最简单粗暴的方式:把所有图片裁成统一的宽×高。
from PIL import Image
import os
def crop_fixed_size(input_dir, output_dir, width, height):
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
continue
img_path = os.path.join(input_dir, filename)
img = Image.open(img_path)
# 左上角裁剪
cropped = img.crop((0, 0, width, height))
cropped.save(os.path.join(output_dir, filename))
print(f"{filename} → {width}x{height}")
# 使用:裁成 800x600
crop_fixed_size(r'D:\原图', r'D:\裁剪后', 800, 600)
⚠️ 如果原图比目标尺寸小,会报错。下面的"居中裁剪"可以解决这个问题。
场景二:居中裁剪成正方形(最常用)
社交媒体头像、商品主图,基本都要正方形。这个方法会自动居中裁剪,不会拉伸变形。
from PIL import Image
import os
def crop_center_square(input_dir, output_dir, size):
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
continue
img_path = os.path.join(input_dir, filename)
img = Image.open(img_path)
# 取最小边作为裁剪尺寸,保证不会切掉内容
min_side = min(img.width, img.height)
left = (img.width - min_side) // 2
top = (img.height - min_side) // 2
right = left + min_side
bottom = top + min_side
cropped = img.crop((left, top, right, bottom))
# 再缩放到目标尺寸(可选)
cropped = cropped.resize((size, size), Image.LANCZOS)
cropped.save(os.path.join(output_dir, filename))
print(f"{filename} → {size}x{size}")
# 使用:裁成 500x500 正方形
crop_center_square(r'D:\照片', r'D:\头像', 500)
效果对比:
| 原图 | 居中裁剪 | 左上角裁剪 |
|---|---|---|
| 1200×800 横图 | ✅ 保留中间主体 | ❌ 只保留左上角 |
| 800×1200 竖图 | ✅ 保留中间主体 | ❌ 只保留左上角 |
场景三:按坐标批量裁剪(精确控制)
有些场景需要精确裁剪某个区域,比如证件照只取头部、截图只取特定区域。
from PIL import Image
import os
def crop_by_coordinates(input_dir, output_dir, coords):
"""
coords: (left, top, right, bottom)
例如:(100, 50, 400, 400) 表示从(100,50)到(400,400)的矩形区域
"""
os.makedirs(output_dir, exist_ok=True)
left, top, right, bottom = coords
crop_width = right - left
crop_height = bottom - top
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.webp')):
continue
img_path = os.path.join(input_dir, filename)
img = Image.open(img_path)
# 判断原图是否够大
if img.width < right or img.height < bottom:
print(f"⚠️ {filename} 尺寸不足,跳过")
continue
cropped = img.crop((left, top, right, bottom))
cropped.save(os.path.join(output_dir, filename))
print(f"{filename} → 裁剪区域 {coords}")
# 使用:裁剪左上角 (100, 50) 到 (600, 550) 的区域
crop_by_coordinates(r'D:\截图', r'D:\裁剪后', (100, 50, 600, 550))
进阶:批量裁剪 + 加水印(一气呵成)
裁剪完直接加上水印,电商场景特别实用。
from PIL import Image, ImageDraw, ImageFont
import os
def crop_and_watermark(input_dir, output_dir, size, watermark_text):
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if not filename.lower().endswith(('.jpg', '.jpeg', '.png')):
continue
img_path = os.path.join(input_dir, filename)
img = Image.open(img_path)
# 居中裁剪
min_side = min(img.width, img.height)
left = (img.width - min_side) // 2
top = (img.height - min_side) // 2
cropped = img.crop((left, top, left + min_side, top + min_side))
cropped = cropped.resize((size, size), Image.LANCZOS)
# 加水印
draw = ImageDraw.Draw(cropped)
font = ImageFont.truetype("simhei.ttf", int(size * 0.08)) # Windows自带黑体
text_bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = text_bbox[2] - text_bbox[0]
x = (size - text_width) // 2
y = size - int(size * 0.1)
draw.text((x, y), watermark_text, fill=(255, 255, 255, 128), font=font)
cropped.save(os.path.join(output_dir, filename), quality=95)
print(f"{filename} → 裁剪+水印完成")
# 使用
crop_and_watermark(r'D:\商品图', r'D:\成品', 800, '店铺名称')
💡 如果是Mac/Linux,字体路径改成
/System/Library/Fonts/Supplemental/Arial Unicode.ttf或安装中文字体。
常见问题速查
| 问题 | 解决方案 |
|---|---|
| 图片有透明通道,保存后变黑底 | 用 cropped.convert('RGB') 转成RGB再保存 |
| 裁剪后图片模糊 | resize() 用 Image.LANCZOS 而不是默认的 Image.BILINEAR |
| 批量处理速度慢 | 考虑用 concurrent.futures.ThreadPoolExecutor 多线程处理 |
| 需要保留EXIF信息 | 用 piexif 库,或 pillow-heif 处理HEIC格式 |
总结
批量裁剪图片的核心就三步:
- 打开图片 →
Image.open() - 裁剪区域 →
img.crop((左, 上, 右, 下)) - 保存结果 →
img.save()
上面的代码覆盖了固定尺寸、居中正方形、精确坐标三种最常见需求,复制过去改一下路径就能跑。
如果你需要更复杂的操作(比如按人脸自动裁剪、批量加圆角),评论区说,我接着写。
更多推荐


所有评论(0)