【问题标题】:PyQt program crashes QPixmap issuePyQt 程序崩溃 QPixmap 问题
【发布时间】:2021-03-04 19:58:40
【问题描述】:

我有一个 PyQt 代码,它不断崩溃给我错误消息QPixmap::fromImage: QPixmap cannot be created without a QGuiApplication QPixmap: Must construct a QGuiApplication before a QPixmap

这是一个相当简单的应用程序,我从一个名为 CameraWidget 的类中读取帧并应用函数 def transform_perspective(self, frame, points) 来获取该帧的变换透视图。我将屏幕分成两部分,右半部分显示相机看到的框架,左半部分显示它的透视变换(为此我从另一个名为 Canvas 的类中获取坐标)。

还有一个问题:左半部分没有占据整个区域。很多部分只是看起来是黑色的。这是一张供您参考的图片

这是一个相当长的程序,所以下面我将包括我认为问题所在的课程。

class TopView(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(TopView, self).__init__(parent)

        self.original_frame = CameraWidget('Abc.ts')

        # Layouts and frames
        self.frame = QtWidgets.QFrame()

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.frame)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(0)
        self.setLayout(layout)

        # frame left
        self.frame_left = QtWidgets.QFrame()

        self.get_frame_thread = Thread(target=self.transform_frame, args=())
        self.get_frame_thread.daemon = True
        self.get_frame_thread.start()

        self.top_view_label = QtWidgets.QLabel()
        self.top_view_label.setScaledContents(True)

        self.layout_left = QtWidgets.QVBoxLayout()
        self.layout_left.addWidget(self.top_view_label)
        self.layout_left.setContentsMargins(0,0,0,0)
        self.layout_left.setSpacing(0)
        self.frame_left.setLayout(self.layout_left)

        # frame right
        self.frame_right = QtWidgets.QFrame()
        self.frame_right.setStyleSheet("background-color: rgb(153, 187, 255)")

        self.video_frame_1 = self.original_frame

        # Create camera widgets
        print('Creating Camera Widgets...')
        self.layout_right = QtWidgets.QVBoxLayout()
        self.layout_right.addWidget(self.video_frame_1)
        self.layout_right.setContentsMargins(5,5,5,5)
        self.frame_right.setLayout(self.layout_right)

        self.layout_inner = QtWidgets.QHBoxLayout()
        self.layout_inner.addWidget(self.frame_left, 50)
        self.layout_inner.addWidget(self.frame_right, 50)
        self.layout_inner.setContentsMargins(0,0,0,0)
        self.layout_inner.setSpacing(0)
        self.frame.setLayout(self.layout_inner)

        self.setLayout(layout)

        sizeObject = QtWidgets.QDesktopWidget().screenGeometry(0)
        self.screen_width = int(0.7*sizeObject.width())
        self.screen_height = int(0.7*sizeObject.height())

    def event(self, e):
        if e.type() in (QtCore.QEvent.Show, QtCore.QEvent.Resize):
            print('')
        return QtWidgets.QWidget.event(self, e)

    def transform_frame(self):
        while True:
            try:
                self.top_view_frame = self.transform_perspective(self.original_frame.get_video_frame(), self.original_frame.canvas.mapped_list)

                h, w, ch = self.top_view_frame.shape
                bytesPerLine = ch * w
                self.img = QtGui.QImage(self.top_view_frame, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
                self.pix = QtGui.QPixmap.fromImage(self.img)
                if not sip.isdeleted(self.top_view_label):
                    self.top_view_label.setPixmap(self.pix)
            
            except Exception as e:
                print(e)

    def transform_perspective(self, frame, points):
        points = np.float32(points)
        p2 = np.float32([[0, 0], [600, 0], [0, 600], [600, 600]])
        self.matrix = cv2.getPerspectiveTransform(points, p2)
        frame = cv2.warpPerspective(frame, self.matrix, (400, 600))

        return frame

【问题讨论】:

  • @eyllanesc 您不能仅从这么多代码中找出问题吗?代码很长,恐怕我很难进一步精简代码。事实上,该代码本身就是 MRE ...link pastebin.com/Mg5Rjhzu
  • 您是否能够仅使用您提供的代码重现该问题?我对此表示怀疑,所以它不可重现。
  • @musicamante 你指的是问题中的代码还是我提供的链接?
  • @Voldemort 它指的是代码,这个链接我们不感兴趣(我什至没有看到它),因为在一段时间内它可能会被破坏,使其对未来的访问者无用。

标签: python python-3.x pyqt pyqt5 qpixmap


【解决方案1】:

虽然 OP 没有提供 MRE,但很容易注意到错误是它正在禁止的辅助线程中创建 QPixmap。相反,您应该将 QImage 发送到 GUI 线程,并在 GUI 线程中将其转换为 QPixmap:

class ImageProcessor(QtCore.QObject):
    imageChanged = QtCore.pyqtSignal(QtGui.QImage)

    def process(self, video_frame, mapped_list):
        thread = Thread(
            target=self._execute,
            args=(
                video_frame,
                mapped_list,
            ),
        )
        thread.daemon = True
        thread.start()

    def _execute(self, video_frame, mapped_list):
        top_view_frame = self.transform_perspective(video_frame, mapped_list)
        qimage = self.convert_np_to_qimage(top_view_frame)
        self.imageChanged.emit(qimage.copy())

    def transform_perspective(self, frame, points):
        points = np.float32(points)
        p2 = np.float32([[0, 0], [600, 0], [0, 600], [600, 600]])
        matrix = cv2.getPerspectiveTransform(points, p2)
        frame = cv2.warpPerspective(frame, matrix, (400, 600))
        return frame

    def convert_np_to_qimage(self, array):
        h, w, ch = array.shape
        bytesPerLine = ch * w
        img = QtGui.QImage(array.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
        return img.copy()


class TopView(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(TopView, self).__init__(parent)

        self.original_frame = CameraWidget("Abc.ts")

        # Layouts and frames
        self.frame = QtWidgets.QFrame()

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.frame)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        # frame left
        self.frame_left = QtWidgets.QFrame()

        self.top_view_label = QtWidgets.QLabel()
        self.top_view_label.setScaledContents(True)

        self.layout_left = QtWidgets.QVBoxLayout(self.frame_left)
        self.layout_left.addWidget(self.top_view_label)
        self.layout_left.setContentsMargins(0, 0, 0, 0)
        self.layout_left.setSpacing(0)

        # frame right
        self.frame_right = QtWidgets.QFrame()
        self.frame_right.setStyleSheet("background-color: rgb(153, 187, 255)")

        self.video_frame_1 = self.original_frame

        # Create camera widgets
        print("Creating Camera Widgets...")
        self.layout_right = QtWidgets.QVBoxLayout(self.frame_right)
        self.layout_right.addWidget(self.video_frame_1)
        self.layout_right.setContentsMargins(5, 5, 5, 5)

        self.layout_inner = QtWidgets.QHBoxLayout(self.frame)
        self.layout_inner.addWidget(self.frame_left, 50)
        self.layout_inner.addWidget(self.frame_right, 50)
        self.layout_inner.setContentsMargins(0, 0, 0, 0)
        self.layout_inner.setSpacing(0)

        sizeObject = QtWidgets.QDesktopWidget().screenGeometry(0)
        self.screen_width = int(0.7 * sizeObject.width())
        self.screen_height = int(0.7 * sizeObject.height())

        self.processor = ImageProcessor()
        self.processor.imageChanged.connect(self.handle_imageChanged)
        self.launch_processor()

    def launch_processor(self):
        self.processor.process(
            self.original_frame.get_video_frame(),
            self.original_frame.canvas.mapped_list,
        )

    @QtCore.pyqtSlot(QtGui.QImage)
    def handle_imageChanged(self, qimage):
        qpixmap = QtGui.QPixmap.fromImage(qimage)
        self.top_view_label.setPixmap(qpixmap)
        QtCore.QTimer.singleShot(0, self.launch_processor)

【讨论】:

  • 您能否解释一下,尽管我提供了setContentsMargins(0,0,0,0),但为什么我在左侧框架中看到这么多黑色空间?
  • @Voldemort 我不知道先生,该代码没有经过测试,因为 OP 没有提供 MRE
猜你喜欢
  • 2016-07-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 2018-05-07
  • 2017-01-27
相关资源
最近更新 更多