Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
622 views
in Technique[技术] by (71.8m points)

python - How to pause and play with 'p' key using cv2.waitKey on qt application

I am using below code.

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Do not modify the class generated by Qt Designer but you must import it into your main script, in this case you must generate the .py again using pyuic5 your_design.ui -o gui.py -x.


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.

This is pointed out in 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.

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

main.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_())

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...