PySide2 QPushButton.setText() завершает работу моего приложения после остановки видеопотока

#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. Это устранило проблему.