Python GigE摄像机的现场视频

Python GigE摄像机的现场视频,python,qt,qml,pyside2,Python,Qt,Qml,Pyside2,我对QML中2个GigE摄像机的实时视频流有问题。我以前用QLabels和QPixmap尝试过,它没有任何问题。QML标签没有pixmap属性,无法使用信号插槽发送图像 以下是我的Python代码: import sys import os from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine from PySide2.QtGui import QImage, QPixm

我对QML中2个GigE摄像机的实时视频流有问题。我以前用QLabels和QPixmap尝试过,它没有任何问题。QML标签没有pixmap属性,无法使用信号插槽发送图像

以下是我的Python代码:

import sys
import os
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtGui import QImage, QPixmap
from PySide2.QtCore import Slot, QThread, Signal, Qt, QObject
import cv2
from pypylon import pylon


tlFactory = pylon.TlFactory.GetInstance()
devices = tlFactory.EnumerateDevices()
if len(devices) == 0:
    raise pylon.RuntimeException("No camera present.")

cameras = pylon.InstantCameraArray(min(len(devices), 2))


for i, cam in enumerate(cameras):
    cam.Attach(tlFactory.CreateDevice(devices[i]))


class CamThread(QThread):
    cam1 = Signal(QImage)
    cam2 = Signal(QImage)

    def run(self):
        cameras.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)

        try:

            while cameras.IsGrabbing():
                grabResult1 = cameras[0].RetrieveResult(
                    5000, pylon.TimeoutHandling_ThrowException
                )
                grabResult2 = cameras[1].RetrieveResult(
                    5000, pylon.TimeoutHandling_ThrowException
                )

                if grabResult1.GrabSucceeded() and grabResult2.GrabSucceeded():
                    img1 = grabResult1.GetArray()
                    img2 = grabResult2.GetArray()
                    rgb1 = cv2.cvtColor(img1, cv2.COLOR_YUV2RGB_Y422)
                    rgb2 = cv2.cvtColor(img2, cv2.COLOR_YUV2RGB_Y422)

                    h1, w1, ch1 = rgb1.shape
                    h2, w2, ch2 = rgb2.shape

                    bytesPerLine1 = ch1 * w1
                    bytesPerLine2 = ch2 * w1
                    convertToQtFormat1 = QImage(
                        img1.data, w1, h1, bytesPerLine1, QImage.Format_RGB888
                    )
                    convertToQtFormat2 = QImage(
                        img2.data, w2, h2, bytesPerLine2, QImage.Format_RGB888
                    )

                    p = convertToQtFormat1.scaled(800, 746, Qt.KeepAspectRatio)
                    q = convertToQtFormat2.scaled(800, 746, Qt.KeepAspectRatio)

                    self.cam1.emit(p)
                    self.cam2.emit(q)

        except Exception as error:
            print(error)


class MainWindow(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.CamThread = CamThread()
        self.CamThread.cam1.connect(self.camera1)
        self.CamThread.cam2.connect(self.camera2)
        self.CamThread.start()

    @Slot(QImage)
    def camera1(self, image):
        pass

    @Slot(QImage)
    def camera2(self, image):
        pass


if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    backend = MainWindow()
    engine = QQmlApplicationEngine()
    engine.rootContext().setContextProperty("backend", backend)
    engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())
那么,如何使用QML/PySide2显示实时视频流呢?
我正在使用QT Design Studio。

QT提供了不同的方法将图像/视频流传递给QML:

1.将pixmap转换为base64编码 此base64编码图像可以传递给

2.使用 这允许连接自定义
image://...
直接指向
QPixmap
QImage
的url。查看文档以了解更多信息

3.使用
特别有用。

虽然QQuickImageProvider选项可能是一个不错的选项,但缺点是您必须生成不同的URL,相反,更好的选项是使用VideoOutput,例如在您的情况下,以下实现应该可以工作(未经测试):

从functools导入缓存的\u属性
导入操作系统
随机输入
导入系统
导入线程
进口cv2
来自PySide2.QtCore导入属性、QObject、Qt、QSize、QTimer、信号、插槽
从PySide2.QtGui导入QColor、qgui应用程序、QImage
从PySide2.QtMultimedia导入QAbstractVideoSurface、QVideoFrame、QVideoSurface格式
从PySide2.QtQml导入QQmlApplicationEngine
进口香菇2
从pypylon导入pypylon
CameraProvider类(QObject):
图像更改=信号(int,QImage)
def启动(自身、摄像头):
threading.Thread(target=self.\u execute,args=(摄像头),daemon=True.start()
def_执行(自身、摄像头):
同时,照相机。正在抓取()
对于i,枚举中的摄影机(摄影机):
尝试:
抓取结果=摄像机[i]。检索结果(
5000,塔架。超时处理\u通过异常
)
如果抓取结果为。抓取成功()
img=grab_result.GetArray()
#修理工
#将img转换为qimage
qimage=qimage(800746,qimage.Format_RGB888)
qimage.fill(QColor(*random.sample(范围为(0255),3)))
如果shiboken2.isValid(self):
self.imageChanged.emit(i,qimage.copy())
除异常作为错误外:
打印(错误)
类摄像机服务(QObject):
表面更改=信号()
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
自曲面=无
self._format=QVideoSurfaceFormat()
self.\u格式\u有效=错误
def get_曲面(自):
返回自曲面
def set_表面(自身,表面):
如果自曲面是曲面:
返回
如果(
self.\u曲面不是无
而self.\u曲面不是曲面
和self.\u surface.isActive()
):
self.\u surface.stop()
自曲面=曲面
self.surfaceChanged.emit()
如果self.\u曲面不是无:
self.\u format=self.\u surface.nearestFormat(self.\u format)
self.\u surface.start(self.\u格式)
videoSurface=属性(
QAbstractVideoSurface,
fget=获取曲面,
fset=设置曲面,
通知=表面更改,
)
@插槽(QImage)
def更新_帧(自身、图像):
如果self.videoSurface为None或qimage.isNull():
返回
如果不是self.\u格式\u有效:
self._set_格式(qimage.width()、qimage.height()、QVideoFrame.format_RGB32)
self.\u格式\u有效=真
qimage.convertTo(
QVideoFrame.imageFormatFromPixelFormat(QVideoFrame.Format_RGB32)
)
自我表面呈现(QVideoFrame(qimage))
def_设置_格式(自身、宽度、高度、像素_格式):
尺寸=QSize(宽度、高度)
视频\格式=QVideoSurfaceFormat(大小、像素\格式)
self.\u格式=视频\u格式
如果self.\u曲面不是无:
如果self.\u surface.isActive():
self.\u surface.stop()
self.\u format=self.\u surface.nearestFormat(self.\u format)
self.\u surface.start(self.\u格式)
类CameraManager(QObject):
def u u init u;(自身、摄像头、父项=无):
super()。\uuuu init\uuuu(父级)
自助服务=[]
self.provider.imageChanged.connect(self.handle\u image\u changed)
self.provider.start(摄像头)
对于内置摄像头:
self.\u services.append(CameraService())
@缓存的不动产
def提供程序(自身):
返回CameraProvider()
@插槽(int,QImage)
def handle_image_已更改(self、index、qimage):
self.\u服务[索引].更新\u框架(qimage)
def get_服务(自助):
返回自助服务
服务=属性(“QVariantList”,fget=get\u服务,常量=True)
def main():
app=qgui应用程序(sys.argv)
tlFactory=pylon.tlFactory.GetInstance()
devices=tlFactory.EnumerateDevices()
如果len(设备)==0:
升起挂架。运行时异常(“不存在摄像头”)
摄像头=挂架。InstantCamerarray(最小(镜头(设备),2))
对于i,枚举中的cam(摄像头):
cam.Attach(tlFactory.CreateDevice(设备[i]))
管理器=摄影机管理器(摄影机)
引擎=QQmlApplicationEngine()
engine.rootContext().setContextProperty(“管理器”,管理器)
load(os.path.join(os.path.dirname(_文件__),“main.qml”))
如果不是engine.rootObjects():
系统出口(-1)
sys.exit(app.exec_())
如果名称=“\uuuuu main\uuuuuuuu”:
main()

我不知道它在Python中是如何工作的,但通常你会使用它。我不确定它在你的情况下是否是一个解决方案,但可能有用。我尝试过,2秒钟后窗口关闭,没有任何错误和警告?@user31562我没有办法测试代码,因为我没有硬件。我一直在测试用随机颜色创建QImage,它们工作正常
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer,"PNG");
QString data("data:image/png;base64,");
data.append(QString::fromLatin1(byteArray.toBase64().data()));
import QtQuick 2.14
import QtQuick.Window 2.14
import QtMultimedia 5.14

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    GridView {
        width: 300; height: 200

        model: manager !== null ? manager.services : []
        delegate: VideoOutput {
            width: 100
            height: 100
            fillMode: VideoOutput.PreserveAspectCrop
            source: model.modelData
        }
    }
}