#python #pyside2
#python #pyside2
Вопрос:
Я создаю виджет, который показывает прямую трансляцию с камеры машинного зрения на пользовательском виджете, полученном из QLabel.
Однако, когда я останавливаю просмотр ленты в реальном времени, моя программа автоматически завершает работу.
Когда я использую отладчик, последняя исполняемая строка находится self.ui.btn_prev_st.setText('Start')
на кнопке, с помощью которой я остановил канал. Если я переступаю через это, я перехожу в update_image()
CameraControl, но приложение закрывается, пока отладчик все еще остановлен.
После этого, app.exec_()
кажется, возвращается, и приложение закрывается.
Для получения изображения я использую pymba. Я вызываю self.cam.disarm()
функцию прямо перед setText()
, но она выполняется нормально, если я выполняю ее. (Он вызывается gc.collect()
в конце, но это ничего не должно делать?)
Так что либо я что-то пропустил в Qt, либо причиной является функция отключения pymba.
У кого-нибудь есть идея? Я привел минимальный рабочий пример.
Заранее спасибо!
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
Комментарии:
1. Это определенно вызвано объектом camera, но я не знаю почему. Когда я не выдаю change_pixmap_signal, приложение не завершает работу.
Ответ №1:
Вместо этого я решил использовать официальную библиотеку VimbyPython. Это устранило проблему.