【问题标题】:How to pause and play with 'p' key using cv2.waitKey on qt application如何在 qt 应用程序上使用 cv2.waitKey 暂停和播放“p”键
【发布时间】:2020-07-29 22:00:12
【问题描述】:

我正在使用下面的代码。

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")      
        MainWindow.resize(640, 480)     
        self.centralwidget = QtWidgets.QWidget(MainWindow)      
        self.centralwidget.setObjectName("centralwidget")   
        self.label = QtWidgets.QLabel(self.centralwidget)   
        self.label.setGeometry(QtCore.QRect(10, 10, 500, 300))  
        self.label.setText("")  
        self.label.setObjectName("label")   
        self.pushButton = QtWidgets.QPushButton(self.centralwidget) 
        self.pushButton.setGeometry(QtCore.QRect(50, 400, 75, 23))  
        self.pushButton.setObjectName("pushButton") 
        MainWindow.setCentralWidget(self.centralwidget) 
        self.statusbar = QtWidgets.QStatusBar(MainWindow)   
        self.statusbar.setObjectName("statusbar")   
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.pushButton.clicked.connect(self.play)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))


    def play(self):     
        cap = cv2.VideoCapture('vtest.asf')
        while True:
            ret, show = cap.read()
            key = cv2.waitKey(1) & 0xFF
            if ret:
                rgbImage = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
                image = QImage(rgbImage.data, show.shape[1], show.shape[0], show.strides[0], QImage.Format_RGB888)
                l = self.label.setPixmap(QPixmap.fromImage(image).scaled(500, 300, Qt.IgnoreAspectRatio))
            if key == ord('p'):
                cv2.waitKey(0)

            elif key == ord('q'):
                break


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

它逐帧显示,但当我使用“p”键盘键时它没有暂停,它不起作用。请让我知道这是正确的方法。请告诉我解决方案。编辑代码。

【问题讨论】:

标签: python python-3.x pyqt5 opencv4


【解决方案1】:

不要修改 Qt Designer 生成的类,但必须将其导入主脚本,在这种情况下,您必须使用 pyuic5 your_design.ui -o gui.py -x 再次生成 .py。


如果显示opencv框架的窗口不是由opencv创建的,则不应使用waitKey(),因为它不会处理键盘事件,也就是说,如果窗口是由X技术生成的,而opencv仅用于获取图像从某些设备上,X 技术必须处理键盘事件。在这种情况下,该技术就是 Qt。

the docs中指出了这一点:

注意:该功能仅在至少有一个HighGUI窗口时有效 已创建并且窗口处于活动状态。如果有几个 HighGUI windows,其中任何一个都可以处于活动状态。

另一方面,读取一帧的任务不会消耗太多时间,所以你不应该使用 while True 因为它阻塞了 GUI 的事件循环,但一个计时器就足够了(在 Qt 的情况下你必须使用一个 QTimer)。

综合以上,解决办法是:

├── gui.py
└── main.py

ma​​in.py

from gui import Ui_MainWindow

from PyQt5 import QtCore, QtGui, QtWidgets

import cv2


class CameraManager(QtCore.QObject):
    frameChanged = QtCore.pyqtSignal(QtGui.QImage)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._capture = None
        self._interval = 30
        self._timer = QtCore.QTimer(
            self, interval=self._interval, timeout=self._on_timeout
        )

    @property
    def capture(self):
        return self._capture

    @capture.setter
    def capture(self, c):
        is_active = self._timer.isActive()
        if is_active:
            self._timer.stop()
        if self.capture is not None:
            self.capture.release()
        self._capture = c
        if is_active:
            self._timer.start()

    @property
    def interval(self):
        return self._interval

    @interval.setter
    def interval(self, t):
        is_active = self._timer.isActive()
        if is_active:
            self._timer.stop()
        self._timer.setInterval(t)
        if is_active:
            self._timer.start()

    @property
    def is_active(self):
        return self._timer.isActive() and self.capture is not None

    @QtCore.pyqtSlot()
    def start(self):
        self._timer.start()

    @QtCore.pyqtSlot()
    def stop(self):
        self._timer.stop()

    @QtCore.pyqtSlot()
    def _on_timeout(self):
        if self.capture is None:
            return
        ret, frame = self.capture.read()
        if ret:
            # https://stackoverflow.com/a/55468544/6622587
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = frame.shape
            bytesPerLine = ch * w
            qImg = QtGui.QImage(
                frame.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888
            )
            self.frameChanged.emit(qImg)


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

        self.camera_manager = CameraManager()
        self.camera_manager.frameChanged.connect(self.on_frame_changed)

        self.camera_manager.capture = cv2.VideoCapture("vtest.asf")

        self.pushButton.clicked.connect(self.camera_manager.start)

        QtWidgets.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key_P), self, activated=self.on_p_pressed
        )

    @QtCore.pyqtSlot(QtGui.QImage)
    def on_frame_changed(self, image):
        pixmap = QtGui.QPixmap.fromImage(image)
        self.label.setPixmap(pixmap)

    @QtCore.pyqtSlot()
    def on_p_pressed(self):
        if self.camera_manager.is_active:
            self.camera_manager.stop()
        else:
            self.camera_manager.start()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

【讨论】:

  • 视频播放速度很慢,按'p'就暂停了。
  • @user3030327 1)为了加快速度,将间隔从 60 更改为 30,2)据我了解,您希望它在按“p”时暂停,对吗?
  • 除了我的第一个问题之外,我怎样才能问第二个问题。有没有可能。
  • @user3030327 你必须创建一个new post。请阅读How to Ask 并查看tour 了解更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2019-05-07
  • 2013-08-09
  • 1970-01-01
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多