如何将matplotlib图转换为pil图像对象(而不保存图像)



作为标题所述,我正在尝试将fig转换为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)

构建无花果后,我已经尝试这样做(它将在出口阶段之前(:

pil_img = Image.frombytes('RGB', canvas.get_width_height(), canvas.tostring_rgb())

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

编辑#2

PIL.Image.frombytes('RGB', 
fig.canvas.get_width_height(),fig.canvas.tostring_rgb())

与下面的35/40ms相比,花费约2毫米。

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


我今天也一直在看这个。

在matplotlib文档中,Savefig函数具有此。

pil_kwargsdict,可选的附加关键字参数已通过保存图形时,要pil.image.save。仅适用于格式使用枕头(即JPEG,TIFF(保存的,(如果关键字是(设置为非单位值(png。

这一定意味着它已经是PIL图像,但我看不到它。

您可以关注此

matplotlib:将图保存到numpy数组

将其放入numpy数组,然后进行

PIL.Image.fromarray(array)

您可能需要使用Array [:, :, ::-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))

结果

%timeit save_plot_and_get()

35.5 ms±148 µs每循环(平均±std。dev。7行,每个循环10循环(

%timeit save_plot_and_get()

35.5 ms±142 µs每循环(平均±std。dev。7行,每个循环10个(

%timeit buffer_plot_and_get()

40.4 ms±152 µs每循环(平均±std。dev。7次,每个循环10循环(

我使用以下功能:

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

示例用法:

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()

我将其标记为重复,然后关闭它,因为我使用了错误的链接。

无论如何,答案可能在这里:

如何将Pylab图保存到可以读取pil image的内存文件中?

不幸的是,这并没有导致任何速度提高,但是如果有人有类似问题,我仍然在下面发布我的特定解决方案:

# 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 = camp)
fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
ax.axis('tight'); ax.axis('off')
# convert to PIL Image object
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi = dpi)
buf.seek(0)
pil_img = deepcopy(Image.open(buf))
buf.close()

最新更新