Я знаю рецепт для отображения массива MxNx3 в виде изображения RGB через Tkinter, но мой рецепт делает несколько копий массива в процессе:
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()
Как мне достичьэквивалентный результат с минимальным количеством копий?
В идеале, я бы создал массив с нулевыми значениями, который представлял бы те же байты, которые использовал объект Tkinter PhotoImage
, фактически давая мне PhotoImage
с изменяемыми значениями пикселей, что делает его дешевым и быстрым для обновления дисплея Tkinter.Я не знаю, как извлечь этот указатель из Tkinter.
Возможно, есть путь через ctypes, как намекал ?
Метод PhotoImage.put()
кажется оченьмедленно, но, возможно, я ошибаюсь, и это путь вперед?
Я попытался создать bytearray()
, содержащий заголовок ppm и значения пикселей изображения, а затем с помощью numpy.frombuffer()
просмотреть значения пикселей изображениякак пустой массив, но я думаю, что конструктор PhotoImage
хочет объект bytes()
, а не объект bytearray()
, а также я думаю, что Tkinter копирует байты своего data
ввода во свой внутренний формат (32-битный RGBA?).Я полагаю, это экономит мне одну копию по сравнению с рецептом выше?