python - 如何在 qt 应用程序上使用 cv2.waitKey 使用 'p' 键暂停和播放

标签 python qt opencv

我正在使用下面的代码。

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”键盘键时它不会暂停,它不起作用。请让我知道这是正确的方法。请告诉我解决方案。编辑后的代码。

最佳答案

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


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

the docs中指出了这一点:

Note: The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active.

另一方面,读取帧的任务不会消耗太多时间,因此您不应该使用 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_())

关于python - 如何在 qt 应用程序上使用 cv2.waitKey 使用 'p' 键暂停和播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61254040/

相关文章:

python - 在 Python 的数组索引中使用 None

python - 如何使用 requirements.txt 在 python 项目中安装所有依赖项

python - updatepkg 使用错误版本的 python 进行软件包安装

c++ - 使用参数列表中的绝对路径启动 QProcess

linux - Linux 中的 Qt 线程问题

c++ - cvStartFindContours 的奇怪问题?

python - 当类的任何属性被修改时,类如何运行某些功能?

c++ - Qt:从主要功能访问小部件并实现退出按钮

python - 如何从 OpenCV "cv2.keypoint"对象中提取 x,y 坐标?

opencv - 使用opencv的立体声图像校正无法正常工作