我知道一种通过Tkinter显示MxNx3 numpy数组作为RGB图像的方法,但我的方法在过程中会制作几份数组副本:
a = np.random.randint(low=255, size=(100, 100, 3), dtype=np.uint8) # Original
ppm_header = b'P6\n%i %i\n255\n'%(a.shape[0], a.shape[1])
a_bytes = a.tobytes() # First copy
ppm_bytes = ppm_header + a_bytes # Second copy https://en.wikipedia.org/wiki/Netpbm_format
root = tk.Tk()
img = tk.PhotoImage(data=ppm_bytes) # Third and fourth copies?
canvas = tk.Canvas(root, width=a.shape[0], height=a.shape[1])
canvas.pack()
canvas.create_image(0, 0, anchor=tk.NW, image=img) # Fifth copy?
root.mainloop()
如何用最少的副本获得相同的结果?
理想情况下,我想创建一个numpy数组,它是与Tkinter的
PhotoImage
对象使用相同字节的视图,有效地给我一个可变像素值的 PhotoImage
,并使其便宜且快速地更新Tkinter显示。我不知道如何从Tkinter中提取这个指针。也许有一种方法可以通过ctypes实现,就像在这里暗示?
PhotoImage.put()
方法似乎非常慢,但也许我错了,这是一条前进的路?我尝试创建一个包含ppm头和图像像素值的
bytearray()
,然后使用numpy.frombuffer()
将图像像素值视为numpy数组,但我认为 PhotoImage
构造函数想要一个 bytes()
对象,而不是一个bytearray()
对象,另外我认为Tkinter会将其 data
输入的字节复制到内部格式(32位RGBA?)。我猜这比上面的方法节省了一个副本?
Tk_PhotoPutBlock()
(这里)。组装它的参数...嗯,这有点棘手。_handle_可以从Tk_FindPhoto()
中获取,但_interp_被埋在Tkinter(Python到Tcl/Tk包装库)中,我不太清楚如何帮助。此外,您必须仅从一个线程使用该代码,否则会遇到严重问题(这是常见的Python/Tkinter问题)。 - Donal Fellows