PySide2 QPushButton.setText() 在停止视频输入后使我的应用程序崩溃
PySide2 QPushButton.setText() crashes my application after halting video feed
我正在创建一个小部件,它在从 QLabel 派生的自定义小部件上显示来自机器视觉相机的实时摄像头源。
但是,当我停止实时查看提要时,我的程序无声地崩溃了。
当我使用调试器时,最后执行的行是 self.ui.btn_prev_st.setText('Start')
在我停止提要的按钮上。如果我越过它,我将进入 CameraControl 的 update_image()
,但应用程序会关闭,而调试器仍处于暂停状态。
在那之后,app.exec_()
似乎 return 并且应用程序关闭。
对于图像采集,我使用 pymba。我在 setText()
之前调用 self.cam.disarm()
函数,但如果我单步执行,它会正常执行。 (它在最后调用 gc.collect()
,但那不应该做任何事情吗?)
所以要么是我在 Qt 中遇到了一些问题,要么是 pymba disarm 函数是原因。
有人有想法吗?我提供了一个最小的工作示例。
提前致谢!
main.py代码:
import sys
import os
import atexit
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile, Signal
from PySide2.QtUiTools import QUiLoader
from ui_main import Ui_main
from camera_control import CameraControl
class main(QMainWindow):
start_acquisition_signal = Signal()
stop_acquisition_signal = Signal()
def __init__(self):
super(main, self).__init__()
self.ui = Ui_main()
self.ui.setupUi(self)
atexit.register(self.cleanup)
self.ui.btn_prev_st.clicked.connect(self.prev_start_pushed)
self.ui.btn_set_roi.clicked.connect(self.ui.camera_prev.apply_roi)
self.ui.btn_reset_roi.clicked.connect(self.ui.camera_prev.reset_roi)
self.start_acquisition_signal.connect(self.ui.camera_prev.start_preview)
self.stop_acquisition_signal.connect(self.ui.camera_prev.stop_preview)
def __del__(self):
del self.ui.camera_prev
def cleanup(self):
del self
def load_ui(self):
loader = QUiLoader()
path = os.path.join(os.path.dirname(__file__), "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
loader.load(ui_file, self)
ui_file.close()
def prev_start_pushed(self, event):
if self.ui.btn_prev_st.text() != 'Stop':
self.start_acquisition_signal.emit()
self.ui.btn_prev_st.setText('Stop')
else:
self.stop_acquisition_signal.emit()
self.ui.btn_prev_st.setText('Start')
if __name__ == "__main__":
app = QApplication([])
widget = main()
widget.show()
sys.exit(app.exec_())
camera_control.py:
from typing import Optional
import cv2
import numpy as np
from pymba import Vimba, Frame
from PySide2 import QtGui
from PySide2.QtWidgets import QLabel
from PySide2.QtCore import Signal, Slot, Qt, QPoint, QRect, QSize
from PySide2.QtGui import QPixmap
class CameraControl(QLabel):
change_pixmap_signal = Signal(np.ndarray)
def __init__(self, parent=None):
super(CameraControl, self).__init__(parent)
self._first_show = True # whether form is shown for the first time
self.is_running = False
self.change_pixmap_signal.connect(self.update_image)
self.vimba = Vimba()
self.vimba.startup()
self.cam = self.vimba.camera(0)
try:
self.cam.close()
except:
pass
self.cam.open()
self.setup_camera()
self.update()
def __del__(self):
try:
self.cam.disarm()
self.cam.close()
except:
pass
del self.vimba
@Slot()
def stop_preview(self):
self.is_running = False
#self.cam.stop_frame_acquisition()
self.cam.disarm()
@Slot()
def start_preview(self):
self.cam.arm('Continuous', self.frame_handler)
self.cam.start_frame_acquisition()
self.is_running = True
def frame_handler(self, frame: Frame, delay: Optional[int] = 1) -> None:
img = frame.buffer_data_numpy()
self.change_pixmap_signal.emit(img)
@Slot(np.ndarray)
def update_image(self, cv_img):
""" Updates the image_label with a new opencv image"""
qt_img = self.convert_cv_qt(cv_img)
self.setPixmap(qt_img)
ui_main.py:
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from camera_control import CameraControl
class Ui_main(object):
def setupUi(self, main):
if not main.objectName():
main.setObjectName(u"main")
main.resize(1192, 752)
self.centralwidget = QWidget(main)
self.centralwidget.setObjectName(u"centralwidget")
self.box_preview = QGroupBox(self.centralwidget)
self.box_preview.setObjectName(u"box_preview")
self.box_preview.setGeometry(QRect(10, 10, 601, 391))
self.btn_prev_st = QPushButton(self.box_preview)
self.btn_prev_st.setObjectName(u"btn_prev_st")
self.btn_prev_st.setGeometry(QRect(20, 20, 75, 23))
self.camera_prev = CameraControl(self.box_preview)
self.camera_prev.setObjectName(u"camera_prev")
self.camera_prev.setGeometry(QRect(110, 20, 480, 360))
self.camera_prev.setMinimumSize(QSize(0, 0))
self.camera_prev.setBaseSize(QSize(640, 480))
self.camera_prev.setMouseTracking(True)
self.camera_prev.setFrameShape(QFrame.Panel)
self.camera_prev.setScaledContents(False)
self.camera_prev.setAlignment(Qt.AlignCenter)
main.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(main)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1192, 21))
main.setMenuBar(self.menubar)
self.statusbar = QStatusBar(main)
self.statusbar.setObjectName(u"statusbar")
main.setStatusBar(self.statusbar)
self.retranslateUi(main)
QMetaObject.connectSlotsByName(main)
# setupUi
def retranslateUi(self, main):
main.setWindowTitle(QCoreApplication.translate("main", u"main", None))
self.box_preview.setTitle(QCoreApplication.translate("main", u"Preview", None))
self.btn_prev_st.setText(QCoreApplication.translate("main", u"Start", None))
# retranslateUi
我决定改用官方 VimbyPython 库。这解决了问题。
我正在创建一个小部件,它在从 QLabel 派生的自定义小部件上显示来自机器视觉相机的实时摄像头源。
但是,当我停止实时查看提要时,我的程序无声地崩溃了。
当我使用调试器时,最后执行的行是 self.ui.btn_prev_st.setText('Start')
在我停止提要的按钮上。如果我越过它,我将进入 CameraControl 的 update_image()
,但应用程序会关闭,而调试器仍处于暂停状态。
在那之后,app.exec_()
似乎 return 并且应用程序关闭。
对于图像采集,我使用 pymba。我在 setText()
之前调用 self.cam.disarm()
函数,但如果我单步执行,它会正常执行。 (它在最后调用 gc.collect()
,但那不应该做任何事情吗?)
所以要么是我在 Qt 中遇到了一些问题,要么是 pymba disarm 函数是原因。
有人有想法吗?我提供了一个最小的工作示例。
提前致谢!
main.py代码:
import sys
import os
import atexit
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile, Signal
from PySide2.QtUiTools import QUiLoader
from ui_main import Ui_main
from camera_control import CameraControl
class main(QMainWindow):
start_acquisition_signal = Signal()
stop_acquisition_signal = Signal()
def __init__(self):
super(main, self).__init__()
self.ui = Ui_main()
self.ui.setupUi(self)
atexit.register(self.cleanup)
self.ui.btn_prev_st.clicked.connect(self.prev_start_pushed)
self.ui.btn_set_roi.clicked.connect(self.ui.camera_prev.apply_roi)
self.ui.btn_reset_roi.clicked.connect(self.ui.camera_prev.reset_roi)
self.start_acquisition_signal.connect(self.ui.camera_prev.start_preview)
self.stop_acquisition_signal.connect(self.ui.camera_prev.stop_preview)
def __del__(self):
del self.ui.camera_prev
def cleanup(self):
del self
def load_ui(self):
loader = QUiLoader()
path = os.path.join(os.path.dirname(__file__), "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
loader.load(ui_file, self)
ui_file.close()
def prev_start_pushed(self, event):
if self.ui.btn_prev_st.text() != 'Stop':
self.start_acquisition_signal.emit()
self.ui.btn_prev_st.setText('Stop')
else:
self.stop_acquisition_signal.emit()
self.ui.btn_prev_st.setText('Start')
if __name__ == "__main__":
app = QApplication([])
widget = main()
widget.show()
sys.exit(app.exec_())
camera_control.py:
from typing import Optional
import cv2
import numpy as np
from pymba import Vimba, Frame
from PySide2 import QtGui
from PySide2.QtWidgets import QLabel
from PySide2.QtCore import Signal, Slot, Qt, QPoint, QRect, QSize
from PySide2.QtGui import QPixmap
class CameraControl(QLabel):
change_pixmap_signal = Signal(np.ndarray)
def __init__(self, parent=None):
super(CameraControl, self).__init__(parent)
self._first_show = True # whether form is shown for the first time
self.is_running = False
self.change_pixmap_signal.connect(self.update_image)
self.vimba = Vimba()
self.vimba.startup()
self.cam = self.vimba.camera(0)
try:
self.cam.close()
except:
pass
self.cam.open()
self.setup_camera()
self.update()
def __del__(self):
try:
self.cam.disarm()
self.cam.close()
except:
pass
del self.vimba
@Slot()
def stop_preview(self):
self.is_running = False
#self.cam.stop_frame_acquisition()
self.cam.disarm()
@Slot()
def start_preview(self):
self.cam.arm('Continuous', self.frame_handler)
self.cam.start_frame_acquisition()
self.is_running = True
def frame_handler(self, frame: Frame, delay: Optional[int] = 1) -> None:
img = frame.buffer_data_numpy()
self.change_pixmap_signal.emit(img)
@Slot(np.ndarray)
def update_image(self, cv_img):
""" Updates the image_label with a new opencv image"""
qt_img = self.convert_cv_qt(cv_img)
self.setPixmap(qt_img)
ui_main.py:
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from camera_control import CameraControl
class Ui_main(object):
def setupUi(self, main):
if not main.objectName():
main.setObjectName(u"main")
main.resize(1192, 752)
self.centralwidget = QWidget(main)
self.centralwidget.setObjectName(u"centralwidget")
self.box_preview = QGroupBox(self.centralwidget)
self.box_preview.setObjectName(u"box_preview")
self.box_preview.setGeometry(QRect(10, 10, 601, 391))
self.btn_prev_st = QPushButton(self.box_preview)
self.btn_prev_st.setObjectName(u"btn_prev_st")
self.btn_prev_st.setGeometry(QRect(20, 20, 75, 23))
self.camera_prev = CameraControl(self.box_preview)
self.camera_prev.setObjectName(u"camera_prev")
self.camera_prev.setGeometry(QRect(110, 20, 480, 360))
self.camera_prev.setMinimumSize(QSize(0, 0))
self.camera_prev.setBaseSize(QSize(640, 480))
self.camera_prev.setMouseTracking(True)
self.camera_prev.setFrameShape(QFrame.Panel)
self.camera_prev.setScaledContents(False)
self.camera_prev.setAlignment(Qt.AlignCenter)
main.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(main)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1192, 21))
main.setMenuBar(self.menubar)
self.statusbar = QStatusBar(main)
self.statusbar.setObjectName(u"statusbar")
main.setStatusBar(self.statusbar)
self.retranslateUi(main)
QMetaObject.connectSlotsByName(main)
# setupUi
def retranslateUi(self, main):
main.setWindowTitle(QCoreApplication.translate("main", u"main", None))
self.box_preview.setTitle(QCoreApplication.translate("main", u"Preview", None))
self.btn_prev_st.setText(QCoreApplication.translate("main", u"Start", None))
# retranslateUi
我决定改用官方 VimbyPython 库。这解决了问题。