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

Python 3.x PyQt5视频播放器:转换为面向对象的代码会阻止播放,python-3.x,class,oop,pyqt5,opencv-python,Python 3.x,Class,Oop,Pyqt5,Opencv Python,我一直在研究如何将视频或直播流整合到应用程序中。我发现了一些工作正常的函数代码: 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...

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

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都是新手,所以任何关于我是如何误解代码的工作方式或者我遗漏了什么的建议都是非常好的。我已经尝试将label设置为全局变量,因为我不确定函数displayFrame()是否知道使用
label.setPixmap
更改哪个标签,但在其他方面我有点不知所措。

在您的第一个示例中,它可以工作,因为
label
是一个全局变量,因此
displayFrame
可以访问它。 在另一种情况下,
标签
仅在
基本窗口
实例的
初始化
范围内声明,因此
显示框架
对此一无所知

使label成为实例(
self.label=QLabel()
)的成员,
displayFrame
成为basicWindow类(
def displayFrame(self):
)的方法,然后正确访问标签;请注意,您还需要使
cap
timer
都成为实例(
self
)的成员,否则它们的对象将在
\uuuu init\uuu
返回后立即被“垃圾收集”

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)

因为你是一个新的面向对象编程,我建议你先学习如何在Python中学习和工作。< /P> AHH,我试着把它变成一个全局变量,没有考虑把它变成一个类变量。我现在就试试,干杯。编辑:恐怕还是不行。Edit2:它甚至没有运行self.displayFrame函数,请在这里输入一个

print(“here”)
进行检查。除非绝对必要,并且只有在您真正知道自己在做什么的情况下,才应该避免使用全局变量(通常,这意味着您可能做错了什么,因为您应该知道永远不应该使用它们:-))。在任何情况下,只有在需要“全局”访问全局函数时才应使用全局函数(不是类成员的函数)。由于
displayFrame
只对basicWindow类实例重要,因此它无论如何都应该是该类的成员,这是OO编程的一个非常重要的方面。@Jkind9对不起,我的错。使计时器成为类的成员(
self.timer=…
)或为其设置父级(
timer=QTimer(self)
)。尝试了这两种方法,但由于某种原因程序正在崩溃。仍然无法看到崩溃前的打印语句运行幸运的是,我无法测试它,因为我现在无法使用cv2。我刚刚发现
cap
也是本地的;让它也成为实例的成员,如果仍然不起作用,请尝试从shell/命令提示符运行代码以查看完整的回溯。