如何在tkinter中显示来自numpy数组的图像?

时间:2018-11-14 21:05:27

标签: python tkinter

以下短代码旨在使用numpy创建一个数组,使用PIL将其转换为图像对象,然后将其插入到tkinter窗口的画布中。

from tkinter import *
from PIL import Image

root = Tk()
array = np.ones((40,40))*150
img = Image.fromarray(array)
canvas = Canvas(root,width=300,height=300)
canvas.pack()
canvas.create_image(20,20,anchor=NW,image=img)

root.mainloop()

这会引发错误:

TclError: image "<PIL.Image.Image image mode=F size=40x40 at 0x7F42D3BC3290>" doesn't exist

2 个答案:

答案 0 :(得分:1)

您需要使用PhotoImage中的ImageTk

执行此操作:

import tkinter as tk
import numpy as np
from PIL import Image, ImageTk

root = tk.Tk()

array = np.ones((40,40))*150
img =  ImageTk.PhotoImage(image=Image.fromarray(array))

canvas = tk.Canvas(root,width=300,height=300)
canvas.pack()
canvas.create_image(20,20, anchor="nw", image=img)

root.mainloop()

答案 1 :(得分:0)

tkinter 仅直接支持几种图像格式,但其中之一,PPM 可以从 numpy 数据轻松创建。因此,这是一个将数组直接转换为 tk.PhotoImage 的解决方案 - 无需绕道(和开销!)ImageTk

import tkinter as tk

import numpy as np


def _photo_image(image: np.ndarray):
    height, width = image.shape
    data = f'P5 {width} {height} 255 '.encode() + image.astype(np.uint8).tobytes()
    return tk.PhotoImage(width=width, height=height, data=data, format='PPM')


root = tk.Tk()

array = np.ones((40, 40)) * 150
img = _photo_image(array)

canvas = tk.Canvas(root, width=300, height=300)
canvas.pack()
canvas.create_image(20, 20, anchor="nw", image=img)

root.mainloop()

神奇之处在于函数 _photo_image 中,它创建一个 portable pixmap 标头并附加图片数据,该数据必须是一个字节数组。

注意事项:

  1. 上面创建了一个便携式灰度图 (PGM)。稍加修改,这也适用于彩色图像。这些还有一个维度。所以,使用

    height, width = image.shape[:2]
    

    提取几何图形和 P6 以便 magic 值传入标题。

    例如,要转换 openCV 图像(通常编码为 BGR),请使用:

    import cv2
    
    def _photo_image(image: np.ndarray):
        height, width = image.shape[:2]
        ppm_header = f'P6 {width} {height} 255 '.encode()
        data = ppm_header + cv2.cvtColor(image, cv2.COLOR_BGR2RGB).tobytes()
        return tk.PhotoImage(width=width, height=height, data=data, format='PPM')
    
  2. 上面指向 English Wikipedia page on netpbm 的链接并没有完全解释标题格式(不过,您可以在示例中找到它)。 German Wikipedia page on portable anymap 有更多关于标题的细节:Magic Value、space、width、space、height、space、max-pixel-value、space