5、Python长图拼接终极指南:Pillow/OpenCV/ImageMagick三方案

Python长图拼接终极指南:Pillow/OpenCV/ImageMagick三方案(含代码+图解)

前言

日常工作中,你是否需要将聊天记录、网页截图、扫描件拼接成一张长图?手动用画图工具拖拽不仅效率低,还容易错位。本文整合三种Python长图拼接方案------纯Python的Pillow(简单易上手)、OpenCV(高性能批量处理)、ImageMagick(外部工具调用,功能强大),覆盖纵向/横向/宫格布局,附完整可复用代码和mermaid图解,帮你一键搞定所有拼接需求!

一、核心方案对比(快速选型)

方案 核心工具 适用场景 优点 缺点
Pillow(推荐入门) PIL/Pillow库 少量图片、简单布局(纵向/横向) 纯Python无依赖、API友好、易调试 大批量/大尺寸图片内存占用高
OpenCV(高性能) OpenCV库 批量处理、大尺寸图片、实时拼接 速度快50%、内存优化好 需熟悉OpenCV数据格式(BGR)
ImageMagick(外部工具) subprocess+ImageMagick 复杂拼接(带特效、格式转换) 功能强大、支持多格式 需额外安装工具、配置环境变量

二、拼接核心流程(mermaid图解)

无论哪种方案,长图拼接的核心逻辑一致,流程如下:

不同对齐方式对比(mermaid示意图)

三、方案详解:关键代码直接复用

1. Pillow方案(入门首选,纯Python无依赖)

适合少量图片拼接,支持对齐、间距、边框、序号等样式,代码直观易调试。

核心代码:纵向拼接(支持居中对齐+间距)
python 复制代码
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path

def stitch_vertical_pillow(image_paths, output_path, spacing=20, align="center", add_border=True):
    """
    Pillow纵向拼接长图
    :param image_paths: 图片路径列表(已排序)
    :param output_path: 输出路径
    :param spacing: 图片间距(像素)
    :param align: 对齐方式(center/left/right)
    :param add_border: 是否添加边框
    """
    # 1. 打开所有图片
    images = [Image.open(path) for path in image_paths]
    
    # 2. 计算画布尺寸
    max_width = max(img.width for img in images)
    total_height = sum(img.height for img in images) + spacing * (len(images) - 1)
    
    # 3. 创建空白画布(白色背景)
    canvas = Image.new("RGB", (max_width, total_height), (255, 255, 255))
    draw = ImageDraw.Draw(canvas)
    
    # 4. 加载字体(用于序号,无则用默认)
    try:
        font = ImageFont.truetype("arial.ttf", 36)
    except:
        font = ImageFont.load_default()
    
    # 5. 逐张粘贴图片
    y_offset = 0
    for idx, img in enumerate(images):
        # 计算水平偏移(对齐)
        if align == "left":
            x_offset = 0
        elif align == "right":
            x_offset = max_width - img.width
        else:
            x_offset = (max_width - img.width) // 2
        
        # 粘贴图片
        canvas.paste(img, (x_offset, y_offset))
        
        # 添加边框
        if add_border:
            draw.rectangle(
                [(x_offset, y_offset), (x_offset + img.width, y_offset + img.height)],
                outline=(200, 200, 200), width=2
            )
        
        # 添加序号
        draw.text((x_offset + 10, y_offset + 10), f"{idx+1:02d}", fill=(128, 128, 128), font=font)
        
        # 更新垂直偏移
        y_offset += img.height + spacing
    
    # 6. 保存结果
    canvas.save(output_path, quality=95)
    print(f"拼接完成!长图保存至:{output_path}(尺寸:{max_width}×{total_height})")

# 使用示例:拼接文件夹下所有PNG/JPG
if __name__ == "__main__":
    img_folder = "./screenshots"
    output = "long_image_pillow.png"
    # 获取排序后的图片路径(按文件名)
    image_paths = sorted([
        str(p) for p in Path(img_folder).glob("*.png")
    ] + [str(p) for p in Path(img_folder).glob("*.jpg")])
    if image_paths:
        stitch_vertical_pillow(image_paths, output, spacing=15, align="center")
    else:
        print("未找到图片文件!")
扩展功能:宫格布局(多行列拼接)
python 复制代码
def stitch_grid_pillow(image_paths, output_path, cols=3, spacing=15):
    """Pillow宫格布局拼接(适合商品展示、多图汇总)"""
    images = [Image.open(path).resize((300, 300), Image.LANCZOS) for path in image_paths]
    rows = (len(images) + cols - 1) // cols  # 向上取整
    
    # 计算画布尺寸
    grid_width = cols * 300 + (cols - 1) * spacing
    grid_height = rows * 300 + (rows - 1) * spacing
    
    canvas = Image.new("RGB", (grid_width, grid_height), (255, 255, 255))
    
    # 逐张粘贴
    for idx, img in enumerate(images):
        row = idx // cols
        col = idx % cols
        x = col * (300 + spacing)
        y = row * (300 + spacing)
        canvas.paste(img, (x, y))
    
    canvas.save(output_path)
    print(f"宫格图保存至:{output_path}({cols}列×{rows}行)")

2. OpenCV方案(高性能,批量处理首选)

OpenCV在内存管理和速度上优于Pillow,适合处理100+张图片或大尺寸截图,批量处理不卡顿。

核心代码:高效纵向拼接
python 复制代码
import cv2
import numpy as np
from pathlib import Path

def stitch_vertical_opencv(image_paths, output_path, spacing=20):
    """
    OpenCV纵向拼接(速度快50%,内存占用低)
    """
    # 1. 读取图片并统一通道(避免灰度图混用)
    images = []
    for path in image_paths:
        img = cv2.imread(path)
        if len(img.shape) == 2:  # 灰度图转BGR
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        images.append(img)
    
    # 2. 计算画布尺寸
    max_width = max(img.shape[1] for img in images)
    total_height = sum(img.shape[0] for img in images) + spacing * (len(images) - 1)
    
    # 3. 创建白色背景画布
    canvas = np.zeros((total_height, max_width, 3), dtype=np.uint8)
    canvas.fill(255)  # 背景色白色
    
    # 4. 粘贴图片(居中对齐)
    y_offset = 0
    for img in images:
        h, w = img.shape[:2]
        x_offset = (max_width - w) // 2
        # 切片赋值(OpenCV高效操作)
        canvas[y_offset:y_offset+h, x_offset:x_offset+w] = img
        y_offset += h + spacing
    
    # 5. 保存(高质量)
    cv2.imwrite(output_path, canvas, [cv2.IMWRITE_JPEG_QUALITY, 95])
    print(f"OpenCV拼接完成!文件:{output_path}")

# 使用示例
if __name__ == "__main__":
    image_paths = sorted(Path("./large_images").glob("*.jpg"))
    stitch_vertical_opencv([str(p) for p in image_paths], "long_image_opencv.jpg")
内存优化:流式处理(超多大图不溢出)
python 复制代码
def stitch_stream_opencv(image_paths, output_path, spacing=20):
    """流式处理:逐张读取,避免一次性加载所有图片"""
    # 第一步:计算总尺寸
    max_width = 0
    total_height = 0
    for path in image_paths:
        img = cv2.imread(path)
        max_width = max(max_width, img.shape[1])
        total_height += img.shape[0] + spacing
        cv2.destroyAllWindows()  # 立即释放
    
    # 第二步:创建画布并分批粘贴
    canvas = np.zeros((total_height, max_width, 3), dtype=np.uint8)
    canvas.fill(255)
    
    y_offset = 0
    for path in image_paths:
        img = cv2.imread(path)
        h, w = img.shape[:2]
        x_offset = (max_width - w) // 2
        canvas[y_offset:y_offset+h, x_offset:x_offset+w] = img
        y_offset += h + spacing
        cv2.destroyAllWindows()
    
    cv2.imwrite(output_path, canvas)
    print(f"流式拼接完成!内存占用始终<100MB")

3. ImageMagick方案(外部工具,功能强大)

通过subprocess调用ImageMagick,支持复杂拼接特效(如渐变、水印),适合纯Python方案无法满足的需求。

核心代码:批量拼接(跨平台)
bash 复制代码
# 先安装ImageMagick:https://imagemagick.org/(配置环境变量)
pip install subprocess-pathlib
python 复制代码
from subprocess import run
from pathlib import Path

def stitch_imagemagick(image_paths, output_path, direction="vertical"):
    """
    调用ImageMagick拼接(支持复杂特效)
    :param direction: vertical(纵向)/horizontal(横向)
    """
    # 构建命令:magick convert + 图片 + 拼接参数 + 输出
    cmd = ["magick", "convert"]
    # 添加拼接方向参数(-append纵向,+append横向)
    cmd.append("-append" if direction == "vertical" else "+append")
    # 添加所有图片路径
    cmd.extend(str(p) for p in image_paths)
    # 添加输出路径
    cmd.append(output_path)
    
    # 执行命令(Windows需shell=True)
    run(cmd, shell=True)
    print(f"ImageMagick拼接完成!文件:{output_path}")

# 使用示例
if __name__ == "__main__":
    image_paths = sorted(Path("./特效图片").glob("*.png"))
    stitch_imagemagick(image_paths, "long_image_magick.png")

四、避坑指南(新手必看)

  1. 图片尺寸不一致 :优先用resize缩放至统一宽度(Pillow/OpenCV),或用填充(白色背景)避免错位;

  2. 内存溢出:大批量图片用OpenCV流式处理,或ImageMagick方案,避免一次性加载所有图片;

  3. 图片方向错误 :通过EXIF信息自动旋转(Pillow示例):

    python 复制代码
    def fix_image_orientation(img):
        from PIL.ExifTags import TAGS
        try:
            for orientation in TAGS.keys():
                if TAGS[orientation] == "Orientation":
                    break
            exif = img._getexif()
            if exif and orientation in exif:
                if exif[orientation] == 6:
                    img = img.rotate(270, expand=True)
                elif exif[orientation] == 8:
                    img = img.rotate(90, expand=True)
        except:
            pass
        return img
  4. ImageMagick路径问题 :Windows需将安装目录(如C:\Program Files\ImageMagick-7.1.1)添加到系统PATH;

  5. 中文路径报错 :将图片路径转为字符串时用str(path),避免编码冲突。

五、实战场景应用

场景1:聊天记录拼接(纵向+序号+边框)

python 复制代码
# 假设聊天截图已按时间排序存放在chat_screenshots文件夹
image_paths = sorted(Path("./chat_screenshots").glob("*.png"))
stitch_vertical_pillow([str(p) for p in image_paths], "chat_long.png", spacing=10, add_border=True)

场景2:网页截图拼接(统一宽度+居中)

python 复制代码
# 缩放所有截图至1080px宽度后拼接
images = [Image.open(p).resize((1080, int(p.height * 1080 / p.width)), Image.LANCZOS) for p in image_paths]
stitch_vertical_pillow(images, "web_long.png", align="center")

场景3:商品图片宫格(3列布局)

python 复制代码
product_images = sorted(Path("./product_photos").glob("*.jpg"))
stitch_grid_pillow(product_images, "product_grid.png", cols=3, spacing=20)

总结

Python长图拼接的核心是"选对方案":入门用Pillow(简单易调试),批量/大尺寸用OpenCV(高性能),复杂特效用ImageMagick(外部工具)。掌握本文的代码和避坑指南,能轻松应对聊天记录、截图、商品图等各类拼接需求,告别手动拖拽的低效操作!

相关推荐
向阳是我1 小时前
v0.app的next.js项目自动部署到宝塔服务器教程
服务器·开发语言·javascript·github·ai编程
重铸码农荣光1 小时前
深入理解 JavaScript 继承:从原型链到 call/apply 的灵活运用
前端·javascript·面试
爱写代码的小朋友1 小时前
OpenCV 视频目标跟踪详解:MeanShift 与 CamShift 算法实战
opencv·目标跟踪
码途进化论1 小时前
前端Docker多平台构建自动化实践
前端·javascript·后端
acethanlic2 小时前
使用Ruff进行Python代码Format、lint和fix
python
codists2 小时前
在 Pycharm 中 debug Scrapy 项目
python
Pyeako2 小时前
操作HTML网页(PyCharm版)
爬虫·python·html
chalmers_152 小时前
require 根据工程目录的相对路径-require新文件实现简单的热更新
linux·前端·javascript
清静诗意2 小时前
Python 异步编程与 Gevent 实战指南
python·协程·gevent