使用时闪烁numpy.ctypeslib.as\u ctypes类型()使用opencv的视频捕获流

2024-04-26 18:16:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我刚开始用pyglet编程。opencv的视频捕获流输出BGR numpy数组,大多数在线教程/解决方案使用数组.tostring()或数组.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()

请参见中的四条线。带有frame_raw[:, ::-1, :].tobytes()的第一行的工作速度约为20FPS。第二个奇怪的是,在黑屏和图像之间有很多交替的闪烁,在闪烁的过程中有些图像被翻转,有些没有!我认为这与如何在较低的级别上查看视图有关,但是当我使用第三行的copy()时,情况就和从未发生过copy一样!当我使用第四行时,没有奇怪的翻转问题,但是闪烁仍然存在。你知道吗

我尝试在配置中禁用double_buffer,并将其传递给窗口的构造函数,但没有起到任何作用。你知道吗

怎么回事?你知道吗

更新:

与Dan Maš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()

Tags: fromimageimportstreamgetrawaswindow