【问题标题】:How to convert Matplotlib figure to PIL Image object (without saving image)如何将 Matplotlib 图形转换为 PIL Image 对象(不保存图像)
【发布时间】:2019-12-10 11:48:32
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    编辑#2

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

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

    这是迄今为止我能找到的最快的方法。


    我今天也在看这个。

    在 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 个循环)

    【讨论】:

    • 请注意,这可能依赖于 matplotlib 后端 - 某些后端(例如 QTAgg)需要通过 fig.canvas.draw() 绘制画布以在使用 tostring_rgb() 之前初始化渲染器。见stackoverflow.com/a/35407794/10342097
    【解决方案2】:

    我使用以下函数:

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

    【讨论】:

    • 这行得通并且非常高效,但是为什么“img.show()”函数会在预览中而不是在 jupyter notebook 中打开图像?
    【解决方案3】:

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

    反正答案可能就在这里:

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

    【讨论】:

    • 谢谢!这绝对是一个改进,因为它是一个Image 对象,它显示了正确的图像,我没有将它保存到磁盘。但是,由于某种原因,图像的分辨率比我将其保存到磁盘然后重新加载时要低得多,这是我在执行此过程时也遇到的问题:icare.univ-lille1.fr/tutorials/convert_a_matplotlib_figure |我将用示例编辑我的帖子
    • 我收回了这一点——我只是忘了包含dpi 参数,这就是为什么分辨率较低的原因。所以谢谢!!我不会将其标记为重复,因为问题略有不同,但如果你觉得是,那么你可以标记。无论哪种方式,都解决了它:)
    【解决方案4】:

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

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

    【讨论】:

    • “深拷贝”在哪里?
    猜你喜欢
    • 1970-01-01
    • 2018-12-30
    • 2017-05-10
    • 2015-12-02
    • 2017-12-20
    • 1970-01-01
    • 2020-05-09
    • 2017-06-29
    • 2018-06-22
    相关资源
    最近更新 更多