如何在 qt 应用程序上使用 cv2.waitKey 暂停和播放“p"键 [英] How to pause and play with 'p' key using cv2.waitKey on qt application

查看:145
本文介绍了如何在 qt 应用程序上使用 cv2.waitKey 暂停和播放“p"键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下代码.

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"键盘键时它没有暂停,它不起作用.请让我知道这是正确的方法.并请告诉我解决方案.修改过的代码.

Its showing frame by frame but its not pausing when i am using 'p' Keyboard key that it's not working. Please let me know that is this correct way. And please show me the solution. Edited code.

推荐答案

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

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

You should not use waitKey() if the window that shows the opencv frame is not created by opencv since it will not handle keyboard events, that is, if the window is generated by X technology and opencv only serves to obtain the image from some device then X technology must handle keyboard events. And in this case that technology is Qt.

这在文档中指出:

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

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).

On the other hand, the task of reading a frame does not consume much time, so you should not use a while True since it blocks the eventloop of the GUI but a timer is enough (in the case of Qt you must use a QTimer).

综合以上,解决办法是:

Considering the above, the solution is:

├── 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_())

这篇关于如何在 qt 应用程序上使用 cv2.waitKey 暂停和播放“p"键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆