PyQt5 视频播放器:转换为面向对象的代码会阻止播放

PyQt5 VideoPlayer: Converting to Object Orientated Code Prevents Playback

我一直在研究如何将视频或直播整合到应用程序中。我发现了一些可以正常工作的功能代码:

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets 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("Vid.mp4")
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_()

我正试图在一些面向对象的代码中使用它,目的是创建一个视频播放小部件以合并到其他应用程序中:

import cv2
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

import qimage2ndarray # for a memory leak,see gist
import sys # for exiting

# Minimal implementation...
class basicWindow(QMainWindow):
    def __init__(self):
        super(basicWindow, self).__init__()

        # OPENCV

        cap = cv2.VideoCapture("Vid.mp4")
        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)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

def displayFrame():
    ret, frame = cap.read()
    if ret:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image = qimage2ndarray.array2qimage(frame)
        try:
            label.setPixmap(QPixmap.fromImage(image))
        except Exception as e:
            print(e)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    windowExample = basicWindow()
    windowExample.show()
    sys.exit(app.exec_())

我是 OO 编码和 PyQt5 的新手,所以任何关于我如何误解代码的工作方式或我遗漏了什么的建议都会很棒。我已经尝试将标签设置为全局变量,因为我不确定函数 displayFrame() 是否知道要使用 label.setPixmap 更改的标签,但除此之外我有点迷茫。

在您的第一个示例中它有效,因为 label 是一个 全局 变量,因此 displayFrame 可以访问它。 在另一种情况下,label 仅在 basicWindow 实例的 __init__ 范围内声明,因此 displayFrame 对此一无所知。

让标签成为实例的成员(self.label = QLabel()),displayFrame成为basicWindow的方法class(def displayFrame(self):),然后正确访问标签;请注意,您还需要使 captimer 成为实例的成员 (self),否则它们的对象将在 __init__ [= 之后立即 "garbage collected" 36=].

class basicWindow(QMainWindow):
    def __init__(self):
        super(basicWindow, self).__init__()
        # ...
        self.cap = cv2.VideoCapture("Vid.mp4")
        # ...
        self.timer = QTimer()
        self.timer.timeout.connect(self.displayFrame)
        self.timer.start(60)
        self.label = QLabel('No Camera Feed')
        # ...

    def displayFrame(self):
        ret, frame = self.cap.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            image = qimage2ndarray.array2qimage(frame)
            try:
                self.label.setPixmap(QPixmap.fromImage(image))
            except Exception as e:
                print(e)

由于您是 OO 编程的新手,我建议您先研究 classes and instances and name resolution 如何在 python 中工作。