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

时间:2019-08-01 20:22:08

标签: python python-3.x numpy matplotlib python-imaging-library

正如标题所述,我正在尝试将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())

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


解决方案

不幸的是,这并没有导致速度提高,但是如果有人遇到类似问题,我仍将在下面发布我的具体解决方案:

# 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')

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

4 个答案:

答案 0 :(得分:3)

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

无论如何答案都可以在这里

how to save a pylab figure into in-memory file which can be read into PIL image?

答案 1 :(得分:3)

编辑#2

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

大约需要2毫秒,而下面的35/40毫秒。

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


我今天也在看这个。

在matplotlib文档中,savefig函数具有此功能。

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

这必须表示它已经是保存之前的pil映像,但我看不到。

您可以遵循此

Matplotlib: save plot to numpy array

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

PIL.Image.fromarray(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(平均±标准偏差,运行7次,每个循环10个循环)

%timeit save_plot_and_get()

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

%timeit buffer_plot_and_get()

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

答案 2 :(得分:1)

我使用以下功能:

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

答案 3 :(得分:0)

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

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