PyQt5-воспроизведение последовательности изображений в QGraphicsView (таинственная утечка памяти)
Я пытаюсь обработать последовательность изображений и сделать видео результатов, используя 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 ответ:
Каждый раз, когда вы используете
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_())