【问题标题】:Videos are playing too fast using OpenCV and PyQT5使用 OpenCV 和 PyQT5 视频播放速度过快
【发布时间】:2021-04-09 13:21:37
【问题描述】:

当在QListWidget 中选择时,我的 GUI 能够自动播放视频。但是,视频播放速度不是正常速度,而是非常快。我以 720p Mp4 视频为例,放在某个文件夹中。我尝试使用cv2.CAP_PROP_FPS 和cv2.CAP_PROP_BUFFERSIZE,但它们都不起作用。我在QThread 和convert_cv_qt 函数中使用了pyqtSignal,我在其他指南中看到了这些函数。 如何以正常速度/帧速率播放视频?

import os
import cv2
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtMultimedia import QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QThread


class VideoThread(QThread):
    change_pixmap_signal = pyqtSignal(np.ndarray)

    def __init__(self, parent=None):
        super(VideoThread, self).__init__(parent)
        self.get_file_dir = self.parent().file_dir #Get the file_dir from UI_MainWindow

    def run(self):
        cap = cv2.VideoCapture(self.get_file_dir)
        
        while True:
            ret, cv_img = cap.read()
            if ret:
                self.change_pixmap_signal.emit(cv_img)
        cap.release()


class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Ui_MainWindow, self).__init__(parent)
        self.setupUI()
    
    def setupUI(self):
        MainWindow.resize(1720, 863)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)
        self.tabWidget.setTabShape(QtWidgets.QTabWidget.Triangular)
        self.tabWidget.setElideMode(QtCore.Qt.ElideNone)
        self.tabWidget.setTabsClosable(False)
        self.tabWidget.setMovable(True)
        self.tab = QtWidgets.QWidget()
        self.videoimage = QtWidgets.QLabel(self.tab)
        self.videoimage.setGeometry(QtCore.QRect(0, 10, 1280, 720))
        self.listWidget = QtWidgets.QListWidget(self.tab)
        self.listWidget.setGeometry(QtCore.QRect(1290, 60, 391, 241))
        self.listWidget.setObjectName("listWidget")
        self.listWidget.itemClicked.connect(self.itemclick)
        self.tabWidget.addTab(self.tab, "")
        self.tabWidget.setTabText(0, "Testing")
        self.verticalLayout_2.addWidget(self.tabWidget)
        MainWindow.setCentralWidget(self.centralwidget)

        self.listvideos()
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    @pyqtSlot(np.ndarray)
    def listvideos(self):
        file_extension = ['avi','mp4','mov']
        arr = os.listdir('D:\\Files\\VSCODE\\APPS\\HDTS\\videos')
        for i in arr:
            for fe in file_extension:
                    if i[-3:] == fe:
                        item = QtWidgets.QListWidgetItem(str(i))
                        self.listWidget.addItem(item)

    def itemclick(self):
        try:
          self.thread.terminate()
        except:
          print("Nothing to terminate!")

        item = self.listWidget.currentItem()
        self.file_dir = 'D:\\Files\\VSCODE\\APPS\\HDTS\\videos\\' + item.text()
        print(self.file_dir)        
        self.thread = VideoThread(self)
        self.thread.change_pixmap_signal.connect(self.update_image)
        self.thread.start()
    
    
    def update_image(self, cv_img):
        qt_img = self.convert_cv_qt(cv_img)
        self.videoimage.setPixmap(qt_img)
    
    def convert_cv_qt(self, cv_img):
        rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
        h, w, ch = rgb_image.shape
        bytes_per_line = ch * w
        convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
        p = convert_to_Qt_format.scaled(1280, 720, Qt.KeepAspectRatio)
        return QtGui.QPixmap.fromImage(p)
    
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    MainWindow.show()
    sys.exit(app.exec_())

【问题讨论】:

  • 请考虑您对setupUi 的实现不是很好,最重要的是因为它在全局 MainWindow 上运行(使用全局变量通常被认为是不好的做法,导致由于实施不佳),而且还因为它可能会导致类和实例出现问题。真的,不要那样做。 Ui_MainWindow 已经是 QMainWindow 的子类,因此您应该仅使用它,而不创建另一个 QMainWindow 实例;然后将setupUi中对MainWindow的所有引用更改为self。
  • 在我学习的过程中,我会尽力听从您的建议。谢谢。

标签: python-3.x opencv pyqt5


【解决方案1】:

当您将 VideoCapture 与文件一起使用时,如果您调用“cap.read()”,您将获得视频的下一帧,而不管其实际帧速率如何。因此,每次捕获帧时都应该使用“msleep”:

def run(self):
    cap = cv2.VideoCapture(self.get_file_dir)
    
    while True:
        ret, cv_img = cap.read()
        if ret:
            self.change_pixmap_signal.emit(cv_img)
        self.msleep(1000//30) # You can change 30 with 60 if you need 60 fps.
    cap.release()

【讨论】:

  • 我尝试了相同的缩进,但它产生了错误:TypeError: arguments did not match any overloaded call: wait(self, msecs: int = ULONG_MAX): argument 1 has unexpected type 'float' wait(self, QDeadlineTimer): argument 1 has unexpected type 'float'
  • @gentales17 我编辑了我的答案,试试这个
  • 它仍然播放得太快。我尝试了30-1000,根本没有任何变化。 self.wait(1000//30)、self.wait(1000//60)、self.wait(1000//100) 和 self.wait(1000//1000)
  • 我不确定那是什么。我只是将值从 30- 更改为 60(如您所建议的),甚至高达 1000,但根本没有任何变化。我也尝试改变缩进,但它也没有工作。我的代码有问题吗?
  • @gentales17 我又编辑了一次,试试这个版本。我认为在这种情况下使用“等待”不是正确的方法。
猜你喜欢
  • 2014-06-06
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2013-11-23
相关资源
最近更新 更多