引言
在图像处理任务中,图片拼接是非常常见的需求:把多张小图拼成一张大图,常用于数据集还原、九宫格图片复原、图像切片后重组、拼图业务等。pillow(pil)通过image.new()创建空白画布 + paste()粘贴图片实现拼接,支持横向拼接、纵向拼接、n×n矩阵拼接。
环境准备
pip install pillow
核心api说明
image.new(mode, size):创建空白画布- mode:图像模式,
rgb彩色,rgba带透明通道 - size:
(width, height)画布宽高
- mode:图像模式,
canvas.paste(image, (x, y)):把图片粘贴到画布的(x,y)坐标位置- x:粘贴起始横坐标
- y:粘贴起始纵坐标
注意:paste不会自动缩放图片,粘贴的子图尺寸必须和预留位置大小匹配。
场景1:横向拼接(左右排列)
把多张图片从左到右拼在一起,所有图片高度必须一致。
from pil import image
from typing import list
def concat_horizontal(img_list: list[image.image]) -> image.image:
"""横向拼接,图片从左向右排列,要求所有图片高度相同"""
if not img_list:
raise valueerror("图片列表不能为空")
# 总宽度为所有图片宽度之和,高度取第一张图高度
total_width = sum(img.width for img in img_list)
height = img_list[0].height
canvas = image.new("rgb", (total_width, height))
offset_x = 0
for img in img_list:
canvas.paste(img, (offset_x, 0))
offset_x += img.width
return canvas
# 示例调用
if __name__ == "__main__":
im1 = image.open("a.jpg")
im2 = image.open("b.jpg")
im3 = image.open("c.jpg")
result = concat_horizontal([im1, im2, im3])
result.save("horizontal.jpg")
场景2:纵向拼接(上下排列)
多张图片从上往下拼接,所有图片宽度必须一致。
def concat_vertical(img_list: list[image.image]) -> image.image:
"""纵向拼接,图片从上向下排列,要求所有图片宽度相同"""
if not img_list:
raise valueerror("图片列表不能为空")
total_height = sum(img.height for img in img_list)
width = img_list[0].width
canvas = image.new("rgb", (width, total_height))
offset_y = 0
for img in img_list:
canvas.paste(img, (0, offset_y))
offset_y += img.height
return canvas
# result = concat_vertical([im1, im2, im3])
# result.save("vertical.jpg")
场景3:n×n矩阵拼接(和之前分割函数配套)
输入子图列表 + 矩阵阶数split_count,输出完整大图。
适用:3×3、4×4九宫格复原,子图尺寸全部相同。
def merge_image_grid(tile_list: list[image.image], split_count: int) -> image.image:
"""
n × n 矩阵拼接,与split_image分割函数配套
:param tile_list: split_image返回的子图列表,行优先顺序
:param split_count: 分割份数,3代表3行3列
:return: 拼接完成的pil image对象
"""
if not tile_list:
raise valueerror("子图列表不能为空")
if len(tile_list) != split_count * split_count:
raise valueerror(f"子图数量不匹配,需要{split_count*split_count}张,实际{len(tile_list)}张")
tile_w, tile_h = tile_list[0].size
canvas_w = tile_w * split_count
canvas_h = tile_h * split_count
canvas = image.new("rgb", (canvas_w, canvas_h))
index = 0
for y in range(split_count):
for x in range(split_count):
canvas.paste(tile_list[index], (x * tile_w, y * tile_h))
index += 1
return canvas
if __name__ == "__main__":
# 和分割代码完整联调示例
from pil import image
from your_module import split_image
big_img = image.open("300x300.jpg")
tiles = split_image(big_img, split_count=3)
merged_img = merge_image_grid(tiles, split_count=3)
merged_img.save("merge_output.jpg")
场景4:自定义行列拼接(m行n列,非正方形)
如果你想要 2行3列,不是n×n正方形矩阵:
def merge_custom_grid(tile_list: list[image.image], rows: int, cols: int) -> image.image:
"""自定义行列矩阵拼接 rows行 cols列"""
tile_w, tile_h = tile_list[0].size
canvas = image.new("rgb", (tile_w * cols, tile_h * rows))
idx = 0
for y in range(rows):
for x in range(cols):
canvas.paste(tile_list[idx], (x * tile_w, y * tile_h))
idx += 1
return canvas
# 示例:2行3列,共6张图片
# out = merge_custom_grid(tiles, rows=2, cols=3)
处理透明通道 rgba
如果你的图片是png带透明,创建画布时把模式改为rgba:
canvas = image.new("rgba", (canvas_w, canvas_h))
常见踩坑点
- 子图尺寸不一致:paste不会自动缩放,子图大小不一样会出现错位、溢出。需要先统一尺寸。
- 图片模式不匹配:rgb图片粘贴到rgba画布可以;rgba粘贴到rgb画布会丢失透明通道,建议统一模式。
- 列表顺序错误:矩阵拼接严格依赖列表顺序,必须和分割时遍历顺序(行优先)保持一致。
- 索引越界:子图数量不等于 rows×cols,直接抛出异常,避免生成错误图片。
完整闭环:分割 + 拼接完整示例
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]:
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)
tile.save(os.path.join(save_dir, f"tile_x{x}_y{y}.png"))
return tile_list
def merge_image_grid(tile_list: list[image.image], split_count: int) -> image.image:
if not tile_list:
raise valueerror("子图列表不能为空")
if len(tile_list) != split_count * split_count:
raise valueerror(f"子图数量不匹配,需要{split_count*split_count}张,实际{len(tile_list)}张")
tile_w, tile_h = tile_list[0].size
canvas_w = tile_w * split_count
canvas_h = tile_h * split_count
canvas = image.new("rgb", (canvas_w, canvas_h))
index = 0
for y in range(split_count):
for x in range(split_count):
canvas.paste(tile_list[index], (x * tile_w, y * tile_h))
index += 1
return canvas
if __name__ == "__main__":
src_img = image.open("test.jpg")
tile_list = split_image(src_img, split_count=3)
print(f"分割得到 {len(tile_list)} 张图片")
restore_img = merge_image_grid(tile_list, split_count=3)
restore_img.save("restore.jpg")
print("完成分割复原,输出 restore.jpg")
总结
image.new()创建空白画布,paste()实现图片粘贴,是pillow拼接的底层核心。- 分为横向、纵向、矩阵n×n三种常用场景;矩阵拼接可以完美复原之前分割出来的图片。
- 注意图片尺寸、图像模式、列表顺序,这三个是拼接出错最高的地方。
- 分割与拼接组合,完成图片切片、复原完整流程,适合数据集预处理、九宫格业务。
拓展方向:可以增加边框、间隙,在子图之间添加空白间隔;也可以增加缩放逻辑自动适配子图大小。
以上就是python使用pillow库实现图片拼接的方法步骤的详细内容,更多关于python pillow库图片拼接的资料请关注代码网其它相关文章!
发表评论