Последовательность воспроизведения изображения в QGraphicsView (Mysterious Memory Leak) - PullRequest
0 голосов
/ 02 июля 2018

Я пытаюсь обработать последовательность изображений и сделать видео с результатами, используя OpenCV и PyQt5. У меня есть какой-то код, который просматривает каталог, читает изображения и пытается отобразить их на QGraphicsView.

def on_start(self):
    for f in self.image_list:
        img = cv2.imread(f)
        img = cv2qimage(img, False)
        self.scene.set_qimage(img)

self.scene наследуется от QGraphicsScene.

  def set_qimage(self, qimage):
        self.pixmap = QPixmap.fromImage(qimage)
        self.addPixmap(self.pixmap)

Проблема в том, что каждый раз, когда я звоню addPixmap(), изображение просто добавляется поверх всех других изображений, и вскоре у меня заканчивается память, и все вылетает. Текущий код не включает ни одного из этапов обработки, он просто конвертирует numpy ndarry в QImage и добавляет QPixmap к сцене.

Как правильно обновить QGraphicsScene, чтобы я мог передавать последовательность изображений?

1 Ответ

0 голосов
/ 02 июля 2018

Каждый раз, когда вы используете addPixmap(), вы создаете новый QGraphicsPixmapItem, добавляющий память без необходимости. Решением является создание QGraphicsPixmapItem и его повторное использование. Кроме того, задача обработки может блокировать основной поток, поэтому вы должны использовать поток для выполнения тяжелой задачи и отправлять QImage через сигналы.

class ProcessWorker(QObject):
    imageChanged = pyqtSignal(QImage)

    def doWork(self):
        for f in self.image_list:
            img = cv2.imread(f)
            img = cv2qimage(img, False)
            self.imageChanged.emit(img)
            QThread.msleep(1)

class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        lay = QVBoxLayout(self)
        gv = QGraphicsView()
        lay.addWidget(gv)
        scene = QGraphicsScene(self)
        gv.setScene(scene)
        self.pixmap_item = QGraphicsPixmapItem()
        scene.addItem(self.pixmap_item)

        self.workerThread = QThread()
        self.worker = ProcessWorker()
        self.worker.moveToThread(self.workerThread)
        self.workerThread.finished.connect(self.worker.deleteLater)
        self.workerThread.started.connect(self.worker.doWork)
        self.worker.imageChanged.connect(self.setImage)
        self.workerThread.start()


    @pyqtSlot(QImage)
    def setImage(self, image):
        pixmap = QPixmap.fromImage(image)
        self.pixmap_item.setPixmap(pixmap)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
...