Python如何分割图片:使用Pillow实现图像等分切割
·
实际开发中经常需要把一张大图均匀切分成多张小图,比如拼图验证码处理、数据集切片、图片九宫格处理。本文基于Python Pillow(PIL)库实现可复用的图片分割函数,支持传入Image对象,返回切割后的子图对象列表,可选择是否落地保存文件。
环境准备
首先安装Pillow库:
pip install pillow
需求说明
- 输入:PIL的
Image图片对象,分割份数N(N×N等分) - 输出:分割之后的子图
Image对象列表,不强制写磁盘,可选保存到本地文件夹 - 示例场景:300×300图片,
split_count=3,输出9张100×100的子图。
完整代码实现
from PIL import Image
import os
from typing import List
def split_image(
img: Image.Image,
split_count: int,
save_dir: str = None
) -> List[Image.Image]:
"""
PIL图片N×N等分分割
:param img: 输入PIL Image对象
:param split_count: 分割份数,3代表3×3,输出9张子图
:param save_dir: 不为None时保存子图到此目录;None不落地磁盘
:return: List[Image.Image] 分割后的子图对象列表
"""
w, h = img.size
tile_w = w // split_count
tile_h = h // split_count
tile_list: List[Image.Image] = []
for y in range(split_count):
for x in range(split_count):
left = x * tile_w
upper = y * tile_h
right = left + tile_w
lower = upper + tile_h
tile = img.crop((left, upper, right, lower))
tile_list.append(tile)
if save_dir is not None:
os.makedirs(save_dir, exist_ok=True)
save_path = os.path.join(save_dir, f"tile_x{x}_y{y}.png")
tile.save(save_path)
return tile_list
if __name__ == "__main__":
# 示例用法
big_img = Image.open("test.jpg")
tiles = split_image(big_img, split_count=3)
print(f"分割得到 {len(tiles)} 张子图")
print(f"单张子图尺寸: {tiles[0].size}")
# 单独保存中间一张图片
# tiles[4].save("middle.png")
# 如果需要全部保存到本地,传入save_dir参数
# tiles = split_image(big_img, split_count=3, save_dir="./split_out")
核心原理讲解
1. Image.crop() 裁剪函数
Pillow中crop((left, upper, right, lower))是图片裁剪核心API,四个参数分别代表:
- left:裁剪区域左边界x坐标
- upper:裁剪区域上边界y坐标
- right:裁剪区域右边界x坐标
- lower:裁剪区域下边界y坐标
2. 坐标计算逻辑
假设原图宽高为w,h,分割份数为split_count:
- 每一小块宽度:
tile_w = w // split_count - 每一小块高度:
tile_h = h // split_count
双层循环,y为行优先外层循环,x为列内层循环。
left = x * tile_w
upper = y * tile_h
right = left + tile_w
lower = upper + tile_h
3. 返回列表的索引顺序(3×3示例)
index:0 → x=0,y=0 | index:1 →x=1,y=0 | index:2 →x=2,y=0
index:3 → x=0,y=1 | index:4 →x=1,y=1 | index:5 →x=2,y=1
index:6 → x=0,y=2 | index:7 →x=1,y=2 | index:8 →x=2,y=2
多种调用示例
示例1:只做内存分割,不保存文件
适合深度学习数据集预处理,直接拿到子图对象做后续处理。
img = Image.open("300x300.jpg")
tile_list = split_image(img, split_count=3)
# tile_list 里面全部是PIL Image对象,可以直接转numpy、做缩放等操作
示例2:分割同时保存全部子图到文件夹
img = Image.open("300x300.jpg")
tile_list = split_image(img, split_count=3, save_dir="./output")
示例3:分割后只保存其中某一张
img = Image.open("300x300.jpg")
tiles = split_image(img, split_count=3)
tiles[4].save("center.png")
⚠️注意事项
- 整除问题:当前代码使用整数除法
//,如果原图宽高不能被split_count整除,图片右下角多余像素会直接丢弃。 - 对象生命周期:返回的子图是裁剪出来的新Image对象,和原图相互独立。
- 本函数只支持N行N列正方形等分;如果需要自定义行列(比如2行3列),可以修改函数增加
rows,cols两个入参。
扩展:配套图片拼接函数
很多场景分割之后还需要把子图列表重新合并回大图,这里提供配套的合并函数:
def merge_images(tile_list: List[Image.Image], split_count: int) -> Image.Image:
"""
将N×N分割得到的子图列表重新拼接回原图
:param tile_list: split_image返回的子图列表
:param split_count: 分割时使用的份数
:return: 拼接完成的PIL Image对象
"""
tile_w, tile_h = tile_list[0].size
out_w = tile_w * split_count
out_h = tile_h * split_count
out_img = Image.new("RGB", (out_w, out_h))
idx = 0
for y in range(split_count):
for x in range(split_count):
out_img.paste(tile_list[idx], (x * tile_w, y * tile_h))
idx += 1
return out_img
# 使用示例
merged = merge_images(tiles, split_count=3)
merged.save("merged.jpg")
总结
- 函数接收PIL Image对象,无需传入文件路径,更适合内存中流水线处理。
- 返回子图对象列表,灵活选择是否写磁盘,适配数据集处理、九宫格、验证码切片等场景。
- 配合merge_images函数,实现分割-拼接完整流程。
完整源码可直接复制运行,可根据业务需求扩展补白逻辑,处理不能整除的图片尺寸。
更多推荐



所有评论(0)