【问题标题】:PyQt showing video stream from opencvPyQt 显示来自 opencv 的视频流
【发布时间】:2017-11-08 07:36:28
【问题描述】:

尝试链接 PyQt 和 Opencv 视频源,无法理解如何应用 while 循环来连续流式传输视频。它只是拍一张静止的照片。请任何人帮忙解决这个问题。

  • PtQt=5

  • Python=3.6.1


class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 Video'
        self.left = 100
        self.top = 100
        self.width = 640
        self.height = 480
        self.initUI()


    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.resize(1800, 1200)
        #create a label
        label = QLabel(self)
        cap = cv2.VideoCapture(0)
        ret, frame = cap.read()
        rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        convertToQtFormat = QtGui.QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0],
                                         QtGui.QImage.Format_RGB888)
        convertToQtFormat = QtGui.QPixmap.fromImage(convertToQtFormat)
        pixmap = QPixmap(convertToQtFormat)
        resizeImage = pixmap.scaled(640, 480, QtCore.Qt.KeepAspectRatio)
        QApplication.processEvents()
        label.setPixmap(resizeImage)
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python opencv pyqt pyqt5 qpixmap


    【解决方案1】:

    为 PySide2 和 qimage2ndarray 更新这个

    from PySide2.QtCore import *
    from PySide2.QtGui import *
    import cv2 # OpenCV
    import qimage2ndarray # for a memory leak,see gist
    import sys # for exiting
    
    # Minimal implementation...
    
    def displayFrame():
        ret, frame = cap.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image = qimage2ndarray.array2qimage(frame)
        label.setPixmap(QPixmap.fromImage(image))
    
    app = QApplication([])
    window = QWidget()
    
    # OPENCV
    
    cap = cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)
    
    # timer for getting frames
    
    timer = QTimer()
    timer.timeout.connect(displayFrame)
    timer.start(60)
    label = QLabel('No Camera Feed')
    button = QPushButton("Quiter")
    button.clicked.connect(sys.exit) # quiter button 
    layout = QVBoxLayout()
    layout.addWidget(button)
    layout.addWidget(label)
    window.setLayout(layout)
    window.show()
    app.exec_()
    
    # See also: https://gist.github.com/bsdnoobz/8464000
    
    

    【讨论】:

    • 非常感谢这个例子!对于 PySide6 导入和 requirements.txt,请参阅我在链接要点中的评论。
    【解决方案2】:

    问题是获取图片的函数只执行了一次,并没有更新标签。
    正确的做法是把它放在一个循环里面,但是这样会导致主窗口阻塞。这种主窗口阻塞可以通过使用QThread 类并通过发送信号QImage 来更新标签来解决。例如:

    import cv2
    import sys
    from PyQt5.QtWidgets import  QWidget, QLabel, QApplication
    from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
    from PyQt5.QtGui import QImage, QPixmap
    
    class Thread(QThread):
        changePixmap = pyqtSignal(QImage)
    
        def run(self):
            cap = cv2.VideoCapture(0)
            while True:
                ret, frame = cap.read()
                if ret:
                    # https://stackoverflow.com/a/55468544/6622587
                    rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    h, w, ch = rgbImage.shape
                    bytesPerLine = ch * w
                    convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                    p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
                    self.changePixmap.emit(p)
    
    
    class App(QWidget):
        def __init__(self):
            super().__init__()
            [...]
            self.initUI()
    
        @pyqtSlot(QImage)
        def setImage(self, image):
            self.label.setPixmap(QPixmap.fromImage(image))
    
        def initUI(self):
            self.setWindowTitle(self.title)
            self.setGeometry(self.left, self.top, self.width, self.height)
            self.resize(1800, 1200)
            # create a label
            self.label = QLabel(self)
            self.label.move(280, 120)
            self.label.resize(640, 480)
            th = Thread(self)
            th.changePixmap.connect(self.setImage)
            th.start()
            self.show()
    

    【讨论】:

    • 你介意在这个答案上加上必要的import 语句,以及使它完整和可运行的任何其他必要的东西吗?
    • 看起来需要 cv2 和 PyQt(4/5)
    【解决方案3】:

    感谢 Taimur Islam 的提问。 感谢 eyllanesc 的精彩回答,我已经稍微修改了您的代码。我用的是PtQt=4 Python=2.7 没用opencv

    import sys    
    import numpy as np
    import flycapture2 as fc2
    
    from PyQt4.QtCore import (QThread, Qt, pyqtSignal)
    from PyQt4.QtGui import (QPixmap, QImage, QApplication, QWidget, QLabel)
    
    class Thread(QThread):
        changePixmap = pyqtSignal(QImage)
    
        def __init__(self, parent=None):
            QThread.__init__(self, parent=parent)       
            self.cameraSettings()
    
    
        def run(self):      
            while True:
                im = fc2.Image()
                self.c.retrieve_buffer(im)
                a = np.array(im)    
    
                rawImage = QImage(a.data, a.shape[1], a.shape[0], QImage.Format_Indexed8)
    
                self.changePixmap.emit(rawImage)
    
        def cameraSettings(self):
            print(fc2.get_library_version())
            self.c = fc2.Context()
            numberCam = self.c.get_num_of_cameras()
            print(numberCam)    
            self.c.connect(*self.c.get_camera_from_index(0))
            print(self.c.get_camera_info())
            m, f = self.c.get_video_mode_and_frame_rate()
            print(m, f)
            print(self.c.get_property_info(fc2.FRAME_RATE))
            p = self.c.get_property(fc2.FRAME_RATE)
            print(p)
            self.c.set_property(**p)
            self.c.start_capture()
    
    
    class App(QWidget):
        def __init__(self):
                super(App,self).__init__()
                self.title = 'PyQt4 Video'
                self.left = 100
                self.top = 100
                self.width = 640
                self.height = 480
                self.initUI()
    
        def initUI(self):
                self.setWindowTitle(self.title)
                self.setGeometry(self.left, self.top, self.width, self.height)
                self.resize(800, 600)
                # create a label
                self.label = QLabel(self)
                self.label.move(0, 0)
                self.label.resize(640, 480)
                th = Thread(self)
                th.changePixmap.connect(lambda p: self.setPixMap(p))
                th.start()
    
        def setPixMap(self, p):     
            p = QPixmap.fromImage(p)    
            p = p.scaled(640, 480, Qt.KeepAspectRatio)
            self.label.setPixmap(p)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        ex = App()
        ex.show()
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 2019-08-13
      • 1970-01-01
      • 2013-10-08
      • 1970-01-01
      • 2017-05-29
      相关资源
      最近更新 更多