使用CV2和Pyglet在Python中捕获Webcam图像

3
我正在使用Python的CV2(OpenCV)和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。

4个回答

1
尽管这种方法可行,但我发现在图像分辨率较高时,从NumPy数组加载图像速度较慢。GitHub上的一个名为pygarrrayimage的Python模块可以直接将NumPy数组加载到显卡中,而无需进行复制。

https://github.com/motmot/pygarrayimage

这使我的Python应用程序从高分辨率视频中加载图像时不会出现滞后。请查看示例文件夹,了解如何快速将图像传输到屏幕上。


0

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

如果您使下面的示例工作,则应该能够在每次调用on_draw时更新pImg,然后您就完成了。

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()

0

您可以使用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

0
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()

1
你能否解释一下这段代码是如何解决问题的? - Harshal Parekh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接