使用带有opencv的VideoCapture流的numpy.ctypeslib.as_ctypes()时闪烁

时间:2017-06-29 21:35:22

标签: python opencv numpy opencv3.0 pyglet

我刚开始使用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()

0 个答案:

没有答案