Python:像素操作性能。嵌入式设备的虚拟桌面
Python: pixel manipulation pefrormance. Virtual desktop for embedded device
我正在寻找一种在 python 中进行像素操作的有效方法。
目标是制作一个 python 脚本作为嵌入式系统的虚拟桌面。
我已经有一个可用的版本,但显示单帧需要一秒以上(太长)。
每秒刷新显示 5 次就好了。
工作原理:
- 有一个带微控制器和显示器的电子设备(128x64px,黑白像素)。
- 有一台 PC 通过 RS-485 连接到它。
- 微控制器中有一个数据缓冲区,代表每个像素。让我们称之为 diplay_buffer.
- Python PC 上的脚本从微控制器下载 diplay_buffer。
- Python 脚本根据来自 diplay_buffer 的数据创建图像。 (我需要优化)
diplay_buffer 是一个 1024 字节的数组。微控制器对其进行准备,然后在实际显示器上显示其内容。我需要使用 python 脚本在 PC 屏幕上显示真实显示器的虚拟副本。
显示方式:
diplay_buffer中的单个位表示单个像素。
显示器有 128x64 像素。 diplay_buffer 中的每个字节代表垂直方向的 8 个像素。前128个字节表示第一行像素(字节中有64px / 8个像素= 8行)。
我使用 python TK 和函数 img.put() 来插入像素。如果位为 1,我插入黑色像素;如果位为 0,我插入白色像素。这是非常无效的。
也许 class 与 PhotoImage 不同,具有更好的像素能力?
我在示例中附加了最少的代码 diplay_buffer。当您 运行 脚本时,您将看到帧和执行时间。
Meybe 会有人帮助尝试优化它吗?
你能告诉我显示像素的更快方法吗?
登德戴尔
Sample frame downloaded from uC
和代码(你可以轻松运行它)
#this script displays value from uC display buffer in a python screen
from tkinter import Tk, Canvas, PhotoImage, mainloop
from math import sin
import time
WIDTH, HEIGHT = 128, 64
ROWS = 8
#some code from tutorial... check what it does:
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg="#ffffff")
canvas.pack()
img = PhotoImage(width=WIDTH, height=HEIGHT)
canvas.create_image((WIDTH/2, HEIGHT/2), image=img, state="normal")
#this is sample screen from uC. It is normally periodically read from uC on runtime to refresh screen view.
diplay_buffer =bytes([16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 130, 254, 130, 0, 0, 254, 32, 16, 8, 254, 0, 254, 144, 144, 144, 128, 0, 124, 130, 130, 130, 124, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 18, 42, 42, 42, 36, 0, 28, 34, 34, 34, 28, 0, 0, 16, 126, 144, 64, 0, 32, 32, 252, 34, 36, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 130, 252, 128, 0, 4, 42, 42, 30, 2, 0, 62, 16, 32, 32, 30, 0, 0, 0, 0, 0, 0, 0, 0, 66, 254, 2, 0, 0, 130, 132, 136, 144, 224, 0, 0, 0, 0, 0, 0, 0, 78, 146, 146, 146, 98, 0, 124, 138, 146, 162, 124, 0, 78, 146, 146, 146, 98, 0, 78, 146, 146, 146, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 254, 16, 16, 16, 254, 0, 28, 42, 42, 42, 24, 0, 0, 130, 254, 2, 0, 0, 0, 130, 254, 2, 0, 0, 28, 34, 34, 34, 28, 0, 0, 0, 0, 0, 0, 0, 254, 144, 144, 144, 128, 0, 62, 16, 32, 32, 16, 0, 0, 34, 190, 2, 0, 0, 28, 42, 42, 42, 24, 0, 62, 16, 32, 32, 30, 0, 28, 34, 34, 20, 254, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 124, 130, 130, 130, 68, 0, 4, 42, 42, 30, 2, 0, 62, 16, 32, 32, 30, 0, 0, 0, 0, 0, 0, 0, 50, 9, 9, 9, 62, 0, 28, 34, 34, 34, 28, 0, 60, 2, 2, 4, 62, 0, 0, 0, 0, 0, 0, 0, 28, 34, 34, 34, 28, 0, 63, 24, 36, 36, 24, 0, 32, 32, 252, 34, 36, 0, 0, 34, 190, 2, 0, 0, 62, 32, 30, 32, 30, 0, 0, 34, 190, 2, 0, 0, 34, 38, 42, 50, 34, 0, 28, 42, 42, 42, 24, 0, 64, 128, 154, 144, 96, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 146, 146, 146, 108, 0, 4, 42, 42, 30, 2, 0, 28, 34, 34, 34, 20, 0, 254, 8, 20, 34, 0, 0, 0, 0])
def get_normalized_bit(value, bit_index):
return (value >> bit_index) & 1
time_start = time.time()
#first pixels are drawn invisible (some kind of frame in python) so set an offset:
x_offset = 2
y_offset = 2
x=x_offset
y=y_offset
#display all uC pixels (single screen frame):
byteIndex=0
for j in range(ROWS): #multiple rows
for i in range(WIDTH): #row
for n in range(8): #byte
if get_normalized_bit(diplay_buffer[byteIndex], 7-n):
img.put("black", (x,y+n))
else:
img.put("white", (x,y+n))
x+=1
byteIndex+=1
x=x_offset
y+=7
time_stop = time.time()
print("Refresh time: ", str(time_stop - time_start), "seconds")
mainloop()
我并没有真正使用 Tkinter,但我读到使用 put()
将单个像素写入图像非常慢。因此,我修改了您的代码以将像素放入 Numpy 数组中,然后使用 PIL 将其转换为 PhotoImage
.
将您的字节缓冲区转换为 PhotoImage
在我的 Mac 上大约需要 1 毫秒。如果将三个 for
循环包装到一个 Numba-jitted 函数中,它可能会快 10-100 倍,但它似乎不值得,因为它可能足够快。
#!/usr/bin/env python3
import numpy as np
from tkinter import *
from PIL import Image, ImageTk
# INSERT YOUR variable display_buffer here <<<
# Make a Numpy array of uint8, that will become
# ... our PIL Image that will become...
# ... a PhotoImage
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
# Make Numpy array into PIL Image
PILImage = Image.fromarray(na)
border = 10
root = Tk()
canvas = Canvas(root, width = 2*border + WIDTH, height = 2*border + HEIGHT)
canvas.pack()
# Make PIL Image into PhotoImage
img = ImageTk.PhotoImage(PILImage)
canvas.create_image(border, border, anchor=NW, image=img)
root.mainloop()
另外,我不知道你的串口线有多快,但是传输1024字节可能需要一些时间,所以你可以考虑启动第二个线程从你的串口中重复读取1024字节并将它们填充到一个 Queue
用于主进程 get()
它们来自。
此外,您可以完全避免使用 Tkinter,只需像这样使用 OpenCV imshow()
:
#!/usr/bin/env python3
import numpy as np
import cv2
# INSERT YOUR display_buffer here <<<
# Make a Numpy array of uint8, that will be displayed
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
while True:
# Display image
cv2.imshow("Virtual Console", na)
# Wait for user to press "q" to quit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
我决定尝试使用 Numba
,提取 128x64 帧的时间减少到 68 微秒。请注意 Python 必须第一次编译,所以我做了一个 warm-up 运行 包含编译然后测量第二个 运行:
#!/usr/bin/env python3
import numba as nb
import numpy as np
from tkinter import *
from PIL import Image, ImageTk
import time
# Make a Numpy array of uint8, that will become
# ... our PIL Image that will become...
# ... a PhotoImage
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
@nb.njit()
def extract(na,display_buffer):
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
return na
# Following is first run which includes compilation time
warmup = extract(na, display_buffer)
# Only time the second run
start = time.time()
na = extract(na, display_buffer)
# Make Numpy array into PIL Image
PILImage = Image.fromarray(na)
elapsed = (time.time()-start)*1000
print(f'Total time: {elapsed} ms') # Reports 0.068 ms
border = 10
root = Tk()
canvas = Canvas(root, width = 2*border + WIDTH, height = 2*border + HEIGHT)
canvas.pack()
# Make PIL Image into PhotoImage
img = ImageTk.PhotoImage(PILImage)
canvas.create_image(border, border, anchor=NW, image=img)
root.mainloop()
我正在寻找一种在 python 中进行像素操作的有效方法。 目标是制作一个 python 脚本作为嵌入式系统的虚拟桌面。 我已经有一个可用的版本,但显示单帧需要一秒以上(太长)。
每秒刷新显示 5 次就好了。
工作原理:
- 有一个带微控制器和显示器的电子设备(128x64px,黑白像素)。
- 有一台 PC 通过 RS-485 连接到它。
- 微控制器中有一个数据缓冲区,代表每个像素。让我们称之为 diplay_buffer.
- Python PC 上的脚本从微控制器下载 diplay_buffer。
- Python 脚本根据来自 diplay_buffer 的数据创建图像。 (我需要优化)
diplay_buffer 是一个 1024 字节的数组。微控制器对其进行准备,然后在实际显示器上显示其内容。我需要使用 python 脚本在 PC 屏幕上显示真实显示器的虚拟副本。
显示方式:
diplay_buffer中的单个位表示单个像素。 显示器有 128x64 像素。 diplay_buffer 中的每个字节代表垂直方向的 8 个像素。前128个字节表示第一行像素(字节中有64px / 8个像素= 8行)。
我使用 python TK 和函数 img.put() 来插入像素。如果位为 1,我插入黑色像素;如果位为 0,我插入白色像素。这是非常无效的。 也许 class 与 PhotoImage 不同,具有更好的像素能力?
我在示例中附加了最少的代码 diplay_buffer。当您 运行 脚本时,您将看到帧和执行时间。
Meybe 会有人帮助尝试优化它吗? 你能告诉我显示像素的更快方法吗?
登德戴尔
Sample frame downloaded from uC
和代码(你可以轻松运行它)
#this script displays value from uC display buffer in a python screen
from tkinter import Tk, Canvas, PhotoImage, mainloop
from math import sin
import time
WIDTH, HEIGHT = 128, 64
ROWS = 8
#some code from tutorial... check what it does:
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg="#ffffff")
canvas.pack()
img = PhotoImage(width=WIDTH, height=HEIGHT)
canvas.create_image((WIDTH/2, HEIGHT/2), image=img, state="normal")
#this is sample screen from uC. It is normally periodically read from uC on runtime to refresh screen view.
diplay_buffer =bytes([16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 130, 254, 130, 0, 0, 254, 32, 16, 8, 254, 0, 254, 144, 144, 144, 128, 0, 124, 130, 130, 130, 124, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 18, 42, 42, 42, 36, 0, 28, 34, 34, 34, 28, 0, 0, 16, 126, 144, 64, 0, 32, 32, 252, 34, 36, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 130, 252, 128, 0, 4, 42, 42, 30, 2, 0, 62, 16, 32, 32, 30, 0, 0, 0, 0, 0, 0, 0, 0, 66, 254, 2, 0, 0, 130, 132, 136, 144, 224, 0, 0, 0, 0, 0, 0, 0, 78, 146, 146, 146, 98, 0, 124, 138, 146, 162, 124, 0, 78, 146, 146, 146, 98, 0, 78, 146, 146, 146, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 254, 16, 16, 16, 254, 0, 28, 42, 42, 42, 24, 0, 0, 130, 254, 2, 0, 0, 0, 130, 254, 2, 0, 0, 28, 34, 34, 34, 28, 0, 0, 0, 0, 0, 0, 0, 254, 144, 144, 144, 128, 0, 62, 16, 32, 32, 16, 0, 0, 34, 190, 2, 0, 0, 28, 42, 42, 42, 24, 0, 62, 16, 32, 32, 30, 0, 28, 34, 34, 20, 254, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 124, 130, 130, 130, 68, 0, 4, 42, 42, 30, 2, 0, 62, 16, 32, 32, 30, 0, 0, 0, 0, 0, 0, 0, 50, 9, 9, 9, 62, 0, 28, 34, 34, 34, 28, 0, 60, 2, 2, 4, 62, 0, 0, 0, 0, 0, 0, 0, 28, 34, 34, 34, 28, 0, 63, 24, 36, 36, 24, 0, 32, 32, 252, 34, 36, 0, 0, 34, 190, 2, 0, 0, 62, 32, 30, 32, 30, 0, 0, 34, 190, 2, 0, 0, 34, 38, 42, 50, 34, 0, 28, 42, 42, 42, 24, 0, 64, 128, 154, 144, 96, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 146, 146, 146, 108, 0, 4, 42, 42, 30, 2, 0, 28, 34, 34, 34, 20, 0, 254, 8, 20, 34, 0, 0, 0, 0])
def get_normalized_bit(value, bit_index):
return (value >> bit_index) & 1
time_start = time.time()
#first pixels are drawn invisible (some kind of frame in python) so set an offset:
x_offset = 2
y_offset = 2
x=x_offset
y=y_offset
#display all uC pixels (single screen frame):
byteIndex=0
for j in range(ROWS): #multiple rows
for i in range(WIDTH): #row
for n in range(8): #byte
if get_normalized_bit(diplay_buffer[byteIndex], 7-n):
img.put("black", (x,y+n))
else:
img.put("white", (x,y+n))
x+=1
byteIndex+=1
x=x_offset
y+=7
time_stop = time.time()
print("Refresh time: ", str(time_stop - time_start), "seconds")
mainloop()
我并没有真正使用 Tkinter,但我读到使用 put()
将单个像素写入图像非常慢。因此,我修改了您的代码以将像素放入 Numpy 数组中,然后使用 PIL 将其转换为 PhotoImage
.
将您的字节缓冲区转换为 PhotoImage
在我的 Mac 上大约需要 1 毫秒。如果将三个 for
循环包装到一个 Numba-jitted 函数中,它可能会快 10-100 倍,但它似乎不值得,因为它可能足够快。
#!/usr/bin/env python3
import numpy as np
from tkinter import *
from PIL import Image, ImageTk
# INSERT YOUR variable display_buffer here <<<
# Make a Numpy array of uint8, that will become
# ... our PIL Image that will become...
# ... a PhotoImage
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
# Make Numpy array into PIL Image
PILImage = Image.fromarray(na)
border = 10
root = Tk()
canvas = Canvas(root, width = 2*border + WIDTH, height = 2*border + HEIGHT)
canvas.pack()
# Make PIL Image into PhotoImage
img = ImageTk.PhotoImage(PILImage)
canvas.create_image(border, border, anchor=NW, image=img)
root.mainloop()
另外,我不知道你的串口线有多快,但是传输1024字节可能需要一些时间,所以你可以考虑启动第二个线程从你的串口中重复读取1024字节并将它们填充到一个 Queue
用于主进程 get()
它们来自。
此外,您可以完全避免使用 Tkinter,只需像这样使用 OpenCV imshow()
:
#!/usr/bin/env python3
import numpy as np
import cv2
# INSERT YOUR display_buffer here <<<
# Make a Numpy array of uint8, that will be displayed
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
while True:
# Display image
cv2.imshow("Virtual Console", na)
# Wait for user to press "q" to quit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
我决定尝试使用 Numba
,提取 128x64 帧的时间减少到 68 微秒。请注意 Python 必须第一次编译,所以我做了一个 warm-up 运行 包含编译然后测量第二个 运行:
#!/usr/bin/env python3
import numba as nb
import numpy as np
from tkinter import *
from PIL import Image, ImageTk
import time
# Make a Numpy array of uint8, that will become
# ... our PIL Image that will become...
# ... a PhotoImage
WIDTH, HEIGHT, ROWS = 128, 64, 8
na = np.zeros((HEIGHT,WIDTH), np.uint8)
@nb.njit()
def extract(na,display_buffer):
idx = 0
x = y = 0
for j in range(ROWS):
for i in range(WIDTH):
b = display_buffer[idx]
for n in range(8):
na[y+n, x] = (1 - ((b >> (7-n)) & 1)) * 255
idx += 1
x += 1
x = 0
y += 7
return na
# Following is first run which includes compilation time
warmup = extract(na, display_buffer)
# Only time the second run
start = time.time()
na = extract(na, display_buffer)
# Make Numpy array into PIL Image
PILImage = Image.fromarray(na)
elapsed = (time.time()-start)*1000
print(f'Total time: {elapsed} ms') # Reports 0.068 ms
border = 10
root = Tk()
canvas = Canvas(root, width = 2*border + WIDTH, height = 2*border + HEIGHT)
canvas.pack()
# Make PIL Image into PhotoImage
img = ImageTk.PhotoImage(PILImage)
canvas.create_image(border, border, anchor=NW, image=img)
root.mainloop()