以下短代码旨在使用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
答案 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 标头并附加图片数据,该数据必须是一个字节数组。
注意事项:
上面创建了一个便携式灰度图 (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')
上面指向 English Wikipedia page on netpbm 的链接并没有完全解释标题格式(不过,您可以在示例中找到它)。 German Wikipedia page on portable anymap 有更多关于标题的细节:Magic Value、space、width、space、height、space、max-pixel-value、space