You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python将多组动画拼接为同画面的单份GIF或短MP4视频

Python 合并多组动画到同一画面的实现方法

下面分两种常见场景给出可直接运行的实现方案:

方案1:已有4个独立GIF,合并为2x2网格布局的单份动图

用Pillow库实现,操作最简便:

  • 先安装依赖:pip install pillow
  • 代码示例:
from PIL import Image, ImageSequence

# 配置参数
GIF_PATHS = ["gif1.gif", "gif2.gif", "gif3.gif", "gif4.gif"] # 替换为你的4个GIF路径
BLOCK_SIZE = (300, 300) # 每个小动图的尺寸,按需调整
GRID_SIZE = (2, 2) # 2行2列布局
OUTPUT_PATH = "merged.gif"
FPS = 10 # 输出帧率,和原GIF保持一致即可

# 读取所有GIF的帧列表
gif_frames = []
max_frames = 0
for path in GIF_PATHS:
    gif = Image.open(path)
    frames = [frame.copy().resize(BLOCK_SIZE) for frame in ImageSequence.Iterator(gif)]
    gif_frames.append(frames)
    max_frames = max(max_frames, len(frames))

# 对齐所有GIF的帧数,短的自动循环补全
for i in range(len(gif_frames)):
    while len(gif_frames[i]) < max_frames:
        gif_frames[i].extend(gif_frames[i])
    gif_frames[i] = gif_frames[i][:max_frames]

# 逐帧拼接
merged_frames = []
for frame_idx in range(max_frames):
    # 新建空白画布
    canvas = Image.new("RGB", (BLOCK_SIZE[0]*GRID_SIZE[0], BLOCK_SIZE[1]*GRID_SIZE[1]))
    # 左上
    canvas.paste(gif_frames[0][frame_idx], (0, 0))
    # 右上
    canvas.paste(gif_frames[1][frame_idx], (BLOCK_SIZE[0], 0))
    # 左下
    canvas.paste(gif_frames[2][frame_idx], (0, BLOCK_SIZE[1]))
    # 右下
    canvas.paste(gif_frames[3][frame_idx], (BLOCK_SIZE[0], BLOCK_SIZE[1]))
    merged_frames.append(canvas)

# 导出GIF
merged_frames[0].save(
    OUTPUT_PATH,
    save_all=True,
    append_images=merged_frames[1:],
    duration=1000//FPS,
    loop=0
)

如果需要导出MP4格式,把拼接好的merged_frames转成numpy数组后用OpenCV的VideoWriter写入即可。

方案2:直接从4组原始图片序列生成合并视频(画质损失更小,推荐)

如果还保留着原始的图片序列,直接从序列拼接效率更高,用OpenCV实现:

  • 先安装依赖:pip install opencv-python numpy
  • 核心逻辑和GIF拼接一致,读取每组序列的对应帧→调整尺寸→拼接→写入视频文件,代码示例如下:
import cv2
import numpy as np
import os

# 配置参数
SEQ_DIRS = ["seq1/", "seq2/", "seq3/", "seq4/"] # 替换为你的4组图片序列文件夹路径
BLOCK_SIZE = (300, 300)
FPS = 10
OUTPUT_PATH = "merged.mp4"

# 读取每组序列的排序后路径
seq_paths = []
min_frames = float("inf")
for dir_path in SEQ_DIRS:
    paths = sorted([os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(('.png', '.jpg'))])
    seq_paths.append(paths)
    min_frames = min(min_frames, len(paths))

# 初始化视频写入器
out_width = BLOCK_SIZE[0] * 2
out_height = BLOCK_SIZE[1] * 2
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video_writer = cv2.VideoWriter(OUTPUT_PATH, fourcc, FPS, (out_width, out_height))

# 逐帧处理
for i in range(min_frames):
    # 读取4帧
    frames = []
    for paths in seq_paths:
        frame = cv2.imread(paths[i])
        frame = cv2.resize(frame, BLOCK_SIZE)
        frames.append(frame)
    # 2x2拼接
    top_row = np.hstack([frames[0], frames[1]])
    bottom_row = np.hstack([frames[2], frames[3]])
    merged_frame = np.vstack([top_row, bottom_row])
    # 写入视频
    video_writer.write(merged_frame)

# 释放资源
video_writer.release()
cv2.destroyAllWindows()

常见注意事项

  • 所有动画/序列的帧率建议统一,避免合并后出现不同步问题
  • 如果各组序列长度不一致,可以循环短序列或者补帧对齐,按需调整即可
  • 导出GIF时如果文件太大,可以适当降低BLOCK_SIZE或者开启optimize=True参数压缩

内容的提问来源于stack exchange,提问作者Wind Circulation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:27:02