【问题标题】:Matplotlib figure to image as a numpy arrayMatplotlib 图以图像为 numpy 数组
【发布时间】:2016-05-23 05:00:51
【问题描述】:

我正在尝试从 Matplotlib 图形中获取一个 numpy 数组图像,我目前正在通过保存到一个文件,然后重新读取该文件来做到这一点,但我觉得必须有更好的方法。这是我现在正在做的事情:

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.gca()

ax.text(0.0,0.0,"Test", fontsize=45)
ax.axis('off')

canvas.print_figure("output.png")
image = plt.imread("output.png")

我试过了:

image = np.fromstring( canvas.tostring_rgb(), dtype='uint8' )

从我找到的一个示例中,但它给了我一个错误,说“FigureCanvasAgg”对象没有属性“renderer”。

【问题讨论】:

    标签: python numpy matplotlib


    【解决方案1】:

    为了得到图形内容为RGB像素值,matplotlib.backend_bases.Renderer需要先绘制canvas的内容。你可以手动调用canvas.draw()

    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure
    
    fig = Figure()
    canvas = FigureCanvas(fig)
    ax = fig.gca()
    
    ax.text(0.0,0.0,"Test", fontsize=45)
    ax.axis('off')
    
    canvas.draw()       # draw the canvas, cache the renderer
    
    image = np.frombuffer(canvas.tostring_rgb(), dtype='uint8')
    

    See here 了解有关 Matplotlib API 的更多信息。

    【讨论】:

    • 我将 img 作为一维数组,您可以使用以下方法解决此问题:width, height = fig.get_size_inches() * fig.get_dpi()img = np.fromstring(canvas.to_string_rgb(), dtype='uint8').reshape(height, width, 3)
    • 我有时会收到一个错误,高度和宽度是浮点数,不过将它们转换为整数很容易解决。
    • 我编辑了答案以包含 @MaxNoe 的建议。
    • 我们真的必须打电话给canvas.draw() 来完成这项工作吗?
    • @RishabhAgrahari 在获取像素值之前,画布的内容需要至少渲染一次。渲染可能是其他操作的副作用,例如如果画布属于 pyplot 图形并且您调用 plt.show() 来显示它,那么画布将被渲染。然而在上面的例子中,如果你摆脱对canvas.draw的调用,你会得到AttributeError: 'FigureCanvasAgg' object has no attribute 'renderer'(试试看)。
    【解决方案2】:

    来自文档:

    https://matplotlib.org/gallery/user_interfaces/canvasagg.html#sphx-glr-gallery-user-interfaces-canvasagg-py

    fig = Figure(figsize=(5, 4), dpi=100)
    # A canvas must be manually attached to the figure (pyplot would automatically
    # do it).  This is done by instantiating the canvas with the figure as
    # argument.
    canvas = FigureCanvasAgg(fig)
    
    # your plotting here
    
    canvas.draw()
    s, (width, height) = canvas.print_to_buffer()
    
    # Option 2a: Convert to a NumPy array.
    X = np.fromstring(s, np.uint8).reshape((height, width, 4))
    

    【讨论】:

      【解决方案3】:

      对于正在搜索此问题的答案的人,这是从以前的答案中收集的代码。请记住,np.fromstring 方法已被弃用,而改用 np.frombuffer

      #Image from plot
      ax.axis('off')
      fig.tight_layout(pad=0)
      
      # To remove the huge white borders
      ax.margins(0)
      
      fig.canvas.draw()
      image_from_plot = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
      image_from_plot = image_from_plot.reshape(fig.canvas.get_width_height()[::-1] + (3,))
      

      【讨论】:

      • @rayryeng-ReinstateMonica 感谢您做出显着改善答案的更改
      • @rayreng 是否可以获得灰度输出?我在画布上没有看到类似于tostring_rgb 的方法
      • 感谢编译答案!我还应该补充一点,命令的顺序(尤其是fig.canvas.draw())非​​常重要。由于排序错误,我的代码最初无法运行。
      【解决方案4】:

      要修复 Jorge 引用的大边距,请添加 ax.margins(0)。详情请见here

      【讨论】:

        【解决方案5】:

        我认为有一些更新,这更容易。

        canvas.draw()
        buf = canvas.buffer_rgba()
        X = np.asarray(buf)
        

        文档中的更新版本:

        from matplotlib.backends.backend_agg import FigureCanvasAgg
        from matplotlib.figure import Figure
        import numpy as np
        
        # make a Figure and attach it to a canvas.
        fig = Figure(figsize=(5, 4), dpi=100)
        canvas = FigureCanvasAgg(fig)
        
        # Do some plotting here
        ax = fig.add_subplot(111)
        ax.plot([1, 2, 3])
        
        # Retrieve a view on the renderer buffer
        canvas.draw()
        buf = canvas.buffer_rgba()
        # convert to a NumPy array
        X = np.asarray(buf)
        

        【讨论】:

        • 这是适合我的版本。 np.fromstring 已弃用,并且在未指定 FigureCanvasAgg 的情况下,某些平台会给出错误,例如在 macOS 上FigureCanvasMac 没有 renderer 属性。我发现这样的操作有多复杂令人难以置信:(
        • 要渲染特定尺寸的图像(例如,1024 x 512 图像),请在构造图形时执行fig = Figure(figsize=(1024, 512), dpi=1)
        • @lingjiankong :不,因为你会得到RuntimeError: In set_size: Could not set the fontsize (error code 0x97),因为dpi 设置得太低而无法渲染字体。更喜欢fig = Figure(figsize=(10.24, 5.12), dpi=100.0),它不会改变最终图片的大小,但这样会更好地取悦matplotlib
        猜你喜欢
        • 1970-01-01
        • 2018-03-21
        • 2021-02-05
        • 2012-06-13
        • 1970-01-01
        • 2019-01-16
        • 1970-01-01
        • 2017-08-23
        • 2010-10-28
        相关资源
        最近更新 更多