从 QPainter/QImage 显示和创建视频

问题描述 投票:0回答:1

我的目标是从 PaintEvents 创建 gif 或视频,并在 QWidget(窗口)上显示。

我尝试将框架绘制到 QImage 上,然后将其渲染到 QWidget 上,但遇到了一些错误。我不确定为什么会出现这样的错误,画家只是在图像上绘画,并且从文档中它说我可以在 end() 之后渲染绘画设备(当我确实将其放在 end 之后时,它会因为不同的原因而抱怨)。

https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QWidget.html#PySide6.QtWidgets.PySide6.QtWidgets.QWidget.render

结束()之前

QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::render: Cannot render with an inactive painter

end()之后,我不应该继承QWidget吗?

QWidget::repaint: Recursive repaint detected
QPainter::begin: A paint device can only be painted by one painter at a time.
QPainter::fillRect: Painter not active
QPainter::scale: Painter not active
QPainter::drawPoints: Painter not active
QPainter::end: Painter not active, aborted
QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::render: Cannot render with an inactive painter
class PlotWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._timer = QTimer(self)
        self._timer.setInterval(100)
        self._timer.timeout.connect(self.frame)

        self._points = QPointList()
        
        self._qimg = QImage(WIDTH, HEIGHT, QImage.Format_RGB32)

    # I simplified the frame def
    def frame(self):
        self._points.clear()
        self._points.append(QPoint(0,0))
        self.update()

    def paintEvent(self, event):
        with QPainter(self._qimg) as painter:
            rect = QRect(QPoint(0, 0), self.size())
            painter.fillRect(rect, Qt.white)
            painter.scale(WIDTH / self._sizeX, HEIGHT / self._sizeY)
            painter.drawPoints(self._points)
            self.render(self._qimg)
        self._qimg.save('test.png', 'PNG') # Id like to later make it into a video. Preferably hold img in memory and append frame to video.
python pyqt pyside6
1个回答
0
投票

我简化了我设想的解决方案的版本。 我使用 imageio 能够通过在每次迭代时附加帧来保存为视频。

您需要 pip install imageio 和 imageio[ffmpeg]

import yaml, os, imageio, numpy as np
from PySide6.QtWidgets import QWidget
from PySide6.QtCore import QPoint, QRect, QTimer, Qt
from PySide6.QtGui import QPainter, QPointList

WIDTH = 720
HEIGHT = 720

class PlotWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._timer = QTimer(self)
        self._timer.setInterval(100)
        self._timer.timeout.connect(self.frame)

        self._points = QPointList()

        self.setFixedSize(WIDTH, HEIGHT)

        self._totalFrames = 10
        self._vid_writer = imageio.get_writer('video.avi', fps=10)

    def closeEvent(self, event):
        self._vid_writer.close()
        self._timer.stop()
        event.accept()

    def frame(self):
        self._points.clear()
        self._points.append(QPoint(0,0))
        
        if self._totalFrames > 0:
            self.update()
            pixmap = self.grab()
            qimg = pixmap.toImage()
            array = np.ndarray((qimg.height(), qimg.width(), 3), buffer=qimg.constBits(), strides=[qimg.bytesPerLine(), 3, 1], dtype=np.uint8)
            if not self._vid_writer.closed:
                self._vid_writer.append_data(array)
        else:
            self._timer.stop()
            self._vid_writer.close()

        self._totalFrames -= 1

    def paintEvent(self, event):
        with QPainter(self) as painter:
            rect = QRect(QPoint(0, 0), self.size())
            painter.fillRect(rect, Qt.white)
            painter.drawPoints(self._points)

© www.soinside.com 2019 - 2024. All rights reserved.