如何将 Matplotlib 图转换为 PIL Image 对象(不保存图像)

Zac*_*ach 15 python numpy matplotlib python-imaging-library python-3.x

正如标题所述,我正在尝试将 a 转换fig为 a PIL.Image。我目前可以通过首先将fig文件保存到磁盘然后使用打开该文件来做到这一点,Image.open()但该过程花费的时间比预期的要长,我希望通过跳过本地保存步骤会快一点。

这是我到目前为止所拥有的:

# build fig
figsize, dpi = self._calc_fig_size_res(img_height)
fig = plt.Figure(figsize=figsize)
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.imshow(torch.from_numpy(S).flip(0), cmap = cmap)
fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
ax.axis('tight'); ax.axis('off')

# export
fig.savefig(export_path, dpi = dpi)

# open image as PIL object
img = Image.open(export_path)
Run Code Online (Sandbox Code Playgroud)

我在构建无花果之后尝试这样做(它会在导出阶段之前):

pil_img = Image.frombytes('RGB', canvas.get_width_height(), canvas.tostring_rgb())
Run Code Online (Sandbox Code Playgroud)

但它没有显示整个图像。它看起来像是左上角的一部分,但它可能只是数据的一种奇怪表示——我正在使用频谱图,因此图像相当抽象。

Lew*_*ris 11

编辑#2

PIL.Image.frombytes('RGB', 
fig.canvas.get_width_height(),fig.canvas.tostring_rgb())
Run Code Online (Sandbox Code Playgroud)

与下面的 35/40ms 相比,大约需要 2ms。

这是目前我能找到的最快的方法。


我今天也在看这个。

在 matplotlib 文档中, savefig 函数有这个。

pil_kwargsdict,可选 保存图形时传递给 PIL.Image.save 的附加关键字参数。仅适用于使用 Pillow 保存的格式,即 JPEG、TIFF 和(如果关键字设置为非 None 值)PNG。

这一定意味着它在保存之前已经是一个 pil 图像,但我看不到它。

你可以按照这个

Matplotlib:将绘图保存到 numpy 数组

将它放入一个 numpy 数组然后执行

PIL.Image.fromarray(数组)

您可能需要使用数组 [:, :, ::-1] 将通道从 BGR 反转为 RGB

编辑:

到目前为止,我已经测试了每种方法。

import io
    
def save_plot_and_get():
    fig.savefig("test.jpg")
    img = cv2.imread("test.jpg")
    return PIL.Image.fromarray(img)
    
def buffer_plot_and_get():
    buf = io.BytesIO()
    fig.savefig(buf)
    buf.seek(0)
    return PIL.Image.open(buf)
    
def from_canvas():
    lst = list(fig.canvas.get_width_height())
    lst.append(3)
    return PIL.Image.fromarray(np.fromstring(fig.canvas.tostring_rgb(),dtype=np.uint8).reshape(lst))
Run Code Online (Sandbox Code Playgroud)

结果

%timeit save_plot_and_get()
Run Code Online (Sandbox Code Playgroud)

每个循环 35.5 ms ± 148 µs(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

%timeit save_plot_and_get()
Run Code Online (Sandbox Code Playgroud)

每个循环 35.5 ms ± 142 µs(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

%timeit buffer_plot_and_get()
Run Code Online (Sandbox Code Playgroud)

每个循环 40.4 ms ± 152 µs(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

  • 请注意,这可能与 matplotlib 后端相关 - 某些后端(例如 QTAgg)需要通过 Fig.canvas.draw() 绘制画布,以在使用 tostring_rgb() 之前初始化渲染器。请参阅/sf/answers/2478545611/ (8认同)

kot*_*ane 5

我使用以下功能:

def fig2img(fig):
    """Convert a Matplotlib figure to a PIL Image and return it"""
    import io
    buf = io.BytesIO()
    fig.savefig(buf)
    buf.seek(0)
    img = Image.open(buf)
    return img

Run Code Online (Sandbox Code Playgroud)

用法示例:

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

x = np.arange(-3,3)
plt.plot(x)
fig = plt.gcf()

img = fig2img(fig)

img.show()

Run Code Online (Sandbox Code Playgroud)