news 2026/8/8 17:52:35

如何使用Python Pillow库实现图片的拼接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何使用Python Pillow库实现图片的拼接

在图像处理任务中,图片拼接是非常常见的需求:把多张小图拼成一张大图,常用于数据集还原、九宫格图片复原、图像切片后重组、拼图业务等。Pillow(PIL)通过Image.new()创建空白画布 +paste()粘贴图片实现拼接,支持横向拼接、纵向拼接、N×N矩阵拼接。

环境准备

pipinstallpillow

核心API说明

  1. Image.new(mode, size):创建空白画布
    • mode:图像模式,RGB彩色,RGBA带透明通道
    • size:(width, height)画布宽高
  2. canvas.paste(image, (x, y)):把图片粘贴到画布的(x,y)坐标位置
    • x:粘贴起始横坐标
    • y:粘贴起始纵坐标

⚠️注意:paste不会自动缩放图片,粘贴的子图尺寸必须和预留位置大小匹配。

场景1:横向拼接(左右排列)

把多张图片从左到右拼在一起,所有图片高度必须一致。

fromPILimportImagefromtypingimportListdefconcat_horizontal(img_list:List[Image.Image])->Image.Image:"""横向拼接,图片从左向右排列,要求所有图片高度相同"""ifnotimg_list:raiseValueError("图片列表不能为空")# 总宽度为所有图片宽度之和,高度取第一张图高度total_width=sum(img.widthforimginimg_list)height=img_list[0].height canvas=Image.new("RGB",(total_width,height))offset_x=0forimginimg_list:canvas.paste(img,(offset_x,0))offset_x+=img.widthreturncanvas# 示例调用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:纵向拼接(上下排列)

多张图片从上往下拼接,所有图片宽度必须一致。

defconcat_vertical(img_list:List[Image.Image])->Image.Image:"""纵向拼接,图片从上向下排列,要求所有图片宽度相同"""ifnotimg_list:raiseValueError("图片列表不能为空")total_height=sum(img.heightforimginimg_list)width=img_list[0].width canvas=Image.new("RGB",(width,total_height))offset_y=0forimginimg_list:canvas.paste(img,(0,offset_y))offset_y+=img.heightreturncanvas# result = concat_vertical([im1, im2, im3])# result.save("vertical.jpg")

场景3:N×N矩阵拼接(和之前分割函数配套)

针对上一篇博客split_image()分割出来的子图列表,行优先还原大图。输入子图列表 + 矩阵阶数split_count,输出完整大图。

适用:3×3、4×4九宫格复原,子图尺寸全部相同。

defmerge_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对象 """ifnottile_list:raiseValueError("子图列表不能为空")iflen(tile_list)!=split_count*split_count:raiseValueError(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=0foryinrange(split_count):forxinrange(split_count):canvas.paste(tile_list[index],(x*tile_w,y*tile_h))index+=1returncanvasif__name__=="__main__":# 和分割代码完整联调示例fromPILimportImagefromyour_moduleimportsplit_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正方形矩阵:

defmerge_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=0foryinrange(rows):forxinrange(cols):canvas.paste(tile_list[idx],(x*tile_w,y*tile_h))idx+=1returncanvas# 示例:2行3列,共6张图片# out = merge_custom_grid(tiles, rows=2, cols=3)

处理透明通道 RGBA

如果你的图片是png带透明,创建画布时把模式改为RGBA

canvas=Image.new("RGBA",(canvas_w,canvas_h))

⚠️常见踩坑点

  1. 子图尺寸不一致:paste不会自动缩放,子图大小不一样会出现错位、溢出。需要先统一尺寸。
  2. 图片模式不匹配:RGB图片粘贴到RGBA画布可以;RGBA粘贴到RGB画布会丢失透明通道,建议统一模式。
  3. 列表顺序错误:矩阵拼接严格依赖列表顺序,必须和分割时遍历顺序(行优先)保持一致。
  4. 索引越界:子图数量不等于 rows×cols,直接抛出异常,避免生成错误图片。

完整闭环:分割 + 拼接完整示例

fromPILimportImageimportosfromtypingimportListdefsplit_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]=[]foryinrange(split_count):forxinrange(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)ifsave_dirisnotNone:os.makedirs(save_dir,exist_ok=True)tile.save(os.path.join(save_dir,f"tile_x{x}_y{y}.png"))returntile_listdefmerge_image_grid(tile_list:List[Image.Image],split_count:int)->Image.Image:ifnottile_list:raiseValueError("子图列表不能为空")iflen(tile_list)!=split_count*split_count:raiseValueError(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=0foryinrange(split_count):forxinrange(split_count):canvas.paste(tile_list[index],(x*tile_w,y*tile_h))index+=1returncanvasif__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")

总结

  1. Image.new()创建空白画布,paste()实现图片粘贴,是Pillow拼接的底层核心。
  2. 分为横向、纵向、矩阵N×N三种常用场景;矩阵拼接可以完美复原之前分割出来的图片。
  3. 注意图片尺寸、图像模式、列表顺序,这三个是拼接出错最高的地方。
  4. 分割与拼接组合,完成图片切片、复原完整流程,适合数据集预处理、九宫格业务。

拓展方向:可以增加边框、间隙,在子图之间添加空白间隔;也可以增加缩放逻辑自动适配子图大小。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/8 17:46:59

Muse Code:面向大型代码库的终端AI智能体部署与实战指南

Meta 最近发布了一个名为 Muse Code 的新项目,它被定位为“面向大型代码库的终端 AI 智能体”。简单来说,这是一个旨在直接在终端里帮你理解和操作大型、复杂代码库的 AI 工具。它不是另一个代码补全插件,而是试图成为一个能理解项目上下文、…

作者头像 李华
网站建设 2026/8/8 17:45:40

3分钟快速上手:用Singularity-LTX-2.3打造你的AI视频生成神器

3分钟快速上手:用Singularity-LTX-2.3打造你的AI视频生成神器 【免费下载链接】Singularity-LTX-2.3_OmniCine_V1 项目地址: https://ai.gitcode.com/hf_mirrors/WarmBloodAban/Singularity-LTX-2.3_OmniCine_V1 你是否想过,将一张静态照片变成生…

作者头像 李华
网站建设 2026/8/8 17:43:45

MCP Inspector:跨平台MCP服务器可视化测试与监控解决方案

MCP Inspector:跨平台MCP服务器可视化测试与监控解决方案 【免费下载链接】inspector Visual testing tool for MCP servers 项目地址: https://gitcode.com/gh_mirrors/inspector1/inspector MCP Inspector是一个面向Model Context Protocol(MCP…

作者头像 李华
网站建设 2026/8/8 17:40:41

界面控件DevExtreme v23.1新版亮点 - 全新的DateRangeBox组件

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NET Core,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac&#xff0c…

作者头像 李华
网站建设 2026/8/8 17:35:08

SavvyCAN:跨平台CAN总线分析的终极免费解决方案

SavvyCAN:跨平台CAN总线分析的终极免费解决方案 【免费下载链接】SavvyCAN QT based cross platform canbus tool 项目地址: https://gitcode.com/gh_mirrors/sa/SavvyCAN 你是否正在寻找一款功能全面、免费且跨平台的CAN总线分析工具?SavvyCAN正…

作者头像 李华