繁体   English   中英

在 Python 中使用 CV2 和 Pyglet 捕获网络摄像头图像

[英]Capture Webcam image using CV2 and Pyglet in Python

我正在使用 CV2 (OpenCV) for Python 和 Pyglet Python 库来创建一个小型应用程序,该应用程序将显示来自网络摄像头的实时视频并覆盖一些文本或静态图像。 我已经用 CV2 制作了一个应用程序,它只在一个框架中显示网络摄像头图像,但现在我想将该框架放入一个 pyglet 窗口中。

到目前为止,这是我拼凑的内容:

import pyglet
from pyglet.window import key
import cv2
import numpy


window = pyglet.window.Window()

camera=cv2.VideoCapture(0)

def getCamFrame(color,camera):
    retval,frame=camera.read()
    if not color:
        frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
    frame=numpy.rot90(frame)
    return frame


frame=getCamFrame(True,camera)
video = pyglet.resource.media(frame, streaming=True)

@window.event
def on_key_press(symbol, modifiers):
    if symbol == key.ESCAPE:
        print 'Application Exited with Key Press'
        window.close()

@window.event
def on_draw():
    window.clear()
    video.blit(10,10)

pyglet.app.run()

运行时,我收到以下错误:

Traceback, line 20 in <module>
  video = pyglet.resource.media(frame, streaming=True)
TypeError: unhashable type: 'numpy.ndarray'

我也愿意接受其他可以让我在实时视频上显示文本的选项。 我最初使用 pygame,但最后,我需要多显示器支持,所以这就是我使用 pyglet 的原因。

您的方法存在许多问题,但最棘手的是将 numpy 数组转换为纹理。 我使用下面的方法,这是我在 SO 其他地方的某个时候发现的。 简而言之,您必须利用pyglet.gl公开的ctypes类型和结构来生成 GLubytes 数组,然后将图像的内容(一个 numpy 数组)放入其中。 然后,因为你有一个一维数组,你必须通过指定像素格式和间距来指定 Pyglet 应该如何制作图像,这里是pImage

如果你让下面的例子工作,你应该能够在每次调用pImg时更新on_draw ,你应该完成。

import pyglet
from pyglet.gl import *
from pyglet.window import key
import cv2
import numpy
import sys

window = pyglet.window.Window()

camera=cv2.VideoCapture(0)

retval,img = camera.read()
sy,sx,number_of_channels = img.shape
number_of_bytes = sy*sx*number_of_channels

img = img.ravel()

image_texture = (GLubyte * number_of_bytes)( *img.astype('uint8') )
# my webcam happens to produce BGR; you may need 'RGB', 'RGBA', etc. instead
pImg = pyglet.image.ImageData(sx,sy,'BGR',
       image_texture,pitch=sx*number_of_channels)

@window.event
def on_key_press(symbol, modifiers):
    if symbol == key.ESCAPE:
        print 'Application Exited with Key Press'
        window.close()

@window.event
def on_draw():
    window.clear()
    pImg.blit(0,0)

pyglet.app.run()

虽然这有效,但我发现当图像是高分辨率时,从 numpy 数组加载图像非常慢。 pygarrrayimage,github上的一个python模块,可以直接将numpy数组加载到显卡中,无需复制:

https://github.com/motmot/pygarrayimage

这使我从高分辨率视频加载图像的 python 应用程序延迟。 查看示例文件夹,了解如何快速将图像 blit 到屏幕上。

您可以使用ImageData 构造函数将每个 opencv 图像转换为 pyglet 图像。 这个想法是将opencv图像转换为PIL数组,然后将其转换为字节字符串,然后作为原始数据传递给构造函数。

from PIL import Image
def cv2glet(img):
    '''Assumes image is in BGR color space. Returns a pyimg object'''
    rows, cols, channels = img.shape
    raw_img = Image.fromarray(img).tobytes()

    top_to_bottom_flag = -1
    bytes_per_row = channels*cols
    pyimg = pyglet.image.ImageData(width=cols, 
                                   height=rows, 
                                   format='BGR', 
                                   data=raw_img, 
                                   pitch=top_to_bottom_flag*bytes_per_row)
    return pyimg
import pyglet
import cv2
window = pyglet.window.Window()

video = cv2.VideoCapture(0)
def takepicture(dt):
    num = 0

    ret,frame = video.read()
    cv2.imwrite(str(num)+'.jpg',frame)
    print("Image_Captured")

@window.event
def on_draw():
    window.clear()
    image = pyglet.image.load('0.jpg')
    image.blit(0,0)

pyglet.clock.schedule_interval(takepicture, 0.001)


pyglet.app.run()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM