我刚开始使用pyglet进行图形编程。 opencv的VideoCapture流输出BGR numpy数组,大多数在线教程/解决方案使用array.tostring()或array.tobyte()让pyglet.image.ImageData构造纹理。它工作但转换速度相对较慢〜每帧30毫秒。然后我开始尝试ctypes数组:
import pyglet
import numpy as np
import cv2
from threading import Thread
stream = cv2.VideoCapture(0)
stream.set(cv2.CAP_PROP_FPS, 30)
_, frame_raw = stream.read()
SCREEN_HEIGHT, SCREEN_WIDTH, NCOLOR = frame_raw.shape
window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
fps_display = pyglet.clock.ClockDisplay()
def get_from_stream():
global frame_raw
while True:
_, frame_raw = stream.read()
thread_get_from_stream = Thread(target=get_from_stream)
thread_get_from_stream.daemon = True
thread_get_from_stream.start()
@window.event
def on_draw():
window.clear()
# image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', frame_raw[:, ::-1, :].tobytes(), -SCREEN_WIDTH * 3) # flip horizontally
image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', np.ctypeslib.as_ctypes(frame_raw[:, ::-1, :].ravel()), -SCREEN_WIDTH * 3) # flip as well
# image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', np.ctypeslib.as_ctypes(frame_raw[:, ::-1, :].copy().ravel()), -SCREEN_WIDTH * 3) # copy and flip
# image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', np.ctypeslib.as_ctypes(frame_raw.ravel()), -SCREEN_WIDTH * 3) # no flip
image.blit(0, 0)
fps_display.draw()
pyglet.clock.schedule_interval(lambda x: None, 1/30.)
pyglet.app.run()
查看on_draw()中的四行。 frame_raw[:, ::-1, :].tobytes()
的第一行工作在〜20FPS。第二个问题很奇怪,黑屏和图像之间有很多闪烁的交替,在闪烁期间,一些图像被翻转,有些则不是!我认为这与如何在较低级别看到视图有关,但是当我使用第三行和副本()时,情况就像复制从未发生过一样!然后,当我使用第四行时,没有奇怪的翻转问题,但闪烁仍然存在。
我尝试在配置中禁用double_buffer
并将其传递给窗口的构造函数,但这没有帮助。
发生了什么事?
更新
与DanMašek讨论。锁定:
import pyglet
import numpy as np
import cv2
from threading import Thread, Lock
stream = cv2.VideoCapture(0)
stream.set(cv2.CAP_PROP_FPS, 30)
_, frame_raw = stream.read()
SCREEN_HEIGHT, SCREEN_WIDTH, NCOLOR = frame_raw.shape
window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
fps_display = pyglet.clock.ClockDisplay()
lock_stream = Lock()
def get_from_stream():
global frame_raw
while True:
with lock_stream:
_, frame_raw = stream.read()
thread_get_from_stream = Thread(target=get_from_stream)
thread_get_from_stream.daemon = True
thread_get_from_stream.start()
@window.event
def on_draw():
window.clear()
with lock_stream:
# image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', frame_raw[:, ::-1, :].tobytes(), -SCREEN_WIDTH * 3)
image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', np.ctypeslib.as_ctypes(frame_raw[:, ::-1, :].ravel()), -SCREEN_WIDTH * 3)
# image = pyglet.image.ImageData(SCREEN_WIDTH, SCREEN_HEIGHT, 'BGR', np.ctypeslib.as_ctypes(frame_raw.ravel()), -SCREEN_WIDTH * 3)
image.blit(0, 0)
fps_display.draw()
pyglet.clock.schedule_interval(lambda x: None, 1/30.)
pyglet.app.run()