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

如何用matplotlib在for循环快速保存大量图片?两类实现性能为何有差异?

两种实现的性能差异原因

  • 方案1的核心问题:没有清理画布上的历史对象。你每次循环调用imshow都会在轴上叠加新的图像艺术家(Artist)对象,旧的对象不会自动销毁。随着循环次数增加,画布上累积的元素越来越多,每次savefig都需要渲染所有累积的对象,耗时会线性增长,内存占用也会持续升高。如果循环次数在10次以内,方案1没有明显性能问题,但循环次数越多,性能下降越明显。
  • 方案2的开销来源:每次循环都要重新创建画布、轴对象,保存后再销毁,虽然有固定的创建/销毁开销,但每次渲染只需要处理3个图像对象,不会有累积开销,循环次数较多时性能反而比方案1更稳定。

for循环中保存图片的最优方案

优先根据你的使用场景选以下方案,性能从高到低排序:

方案A:跳过matplotlib,直接用PIL拼接保存

如果你的需求只是把三张图横向拼接输出、不需要加坐标轴/标注等matplotlib可视化元素,这是最快的方案,速度比matplotlib方案快5~10倍。参考代码:

from PIL import Image

def concat_3img_horizontal(img1, img2, img3, padding=0):
    # 假设三个图尺寸相同,尺寸不同可先自行resize对齐
    w, h = img1.size
    total_w = w * 3 + padding * 2
    new_img = Image.new('RGB', (total_w, h))
    new_img.paste(img1, (0, 0))
    new_img.paste(img2, (w + padding, 0))
    new_img.paste(img3, (w*2 + padding*2, 0))
    return new_img

for k, fname in enumerate(list_of_fnames):
    with Image.open(fname) as img:
        x = img.convert('RGB')
    # 处理函数可适配为直接操作PIL对象,或者处理完转回PIL对象
    y = process_image_fn1_pil(x)
    z = process_image_fn2_pil(x)
    concat_img = concat_3img_horizontal(x, y, z)
    # compress_level设为1可大幅提升保存速度,仅文件体积稍大
    concat_img.save(f'results_{k}.png', compress_level=1)

方案B:复用画布+仅更新图像数据

如果必须使用matplotlib(需要加标注、坐标轴等可视化元素),该方案比方案2快2~3倍,核心逻辑是只创建一次imshow对象,后续循环直接更新图像数据,避免对象重复创建和累积。参考代码:

import matplotlib
# 一定要在import pyplot之前设置非交互后端,避免GUI相关开销
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image

# 关闭交互模式
plt.ioff()

# 提前创建画布和轴
fig, a = plt.subplots(1, 3, figsize=(30, 20))
# 预创建imshow对象,后续仅更新数据
im0 = a[0].imshow(np.zeros((1,1,3), dtype=np.uint8))
im1 = a[1].imshow(np.zeros((1,1,3), dtype=np.uint8))
im2 = a[2].imshow(np.zeros((1,1,3), dtype=np.uint8))

# 不需要坐标轴可直接关闭,减少渲染开销
for ax in a:
    ax.set_axis_off()

# list_of_fnames为文件名列表
for k, fname in enumerate(list_of_fnames):
    with Image.open(fname) as img:
        x = np.array(img)
    y = process_image_fn1(x)
    z = process_image_fn2(x)
    
    # 直接更新图像数据,不创建新对象
    im0.set_data(x)
    im1.set_data(y)
    im2.set_data(z)
    
    # 如果你的图像数据范围固定,可省略autoscale步骤,速度更快
    im0.autoscale()
    im1.autoscale()
    im2.autoscale()

    output_filename = f'results_{k}.png'
    plt.savefig(
        output_filename, 
        dpi=320, 
        format='png', 
        transparent=False, 
        bbox_inches='tight', 
        pad_inches=0,
        # 降低PNG压缩级别,大幅提升保存速度
        pil_kwargs={"compress_level": 1}
    )
# 所有循环结束后再销毁画布
plt.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 10:06:01