如何在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"键盘键时,它不会暂停。请让我知道这是正确的方式。请给我看看解决方案。已编辑代码。

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


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

文件中指出了这一点:

注意:只有在至少有一个HighGUI窗口的情况下,该函数才能工作创建并且窗口处于活动状态。如果有几个HighGUI窗口,其中任何一个都可以处于活动状态。

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

考虑到以上情况,解决方案是:

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

最新更新