问题描述
我正在尝试使用 OpenCV 和 PyQt5 处理图像序列并制作结果视频.我有一些代码循环遍历目录、读取图像并尝试在QGraphicsView上显示它们.
I'm trying to process an image sequence and make a video of the results using OpenCV and PyQt5. I've got some code that loops through a directory, reads in the images, and tries to display them on a 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 添加到场景中.
The problem is everytime I call addPixmap() the image is just added on top of all the other images and soon I run out of memory and everything crashes. The current code doesn't include any of the processing steps, it just converts the numpy ndarry to a QImage and adds the QPixmap to the scene.
更新 QGraphicsScene 以便我可以流式传输一系列图像的正确方法是什么?
推荐答案
每次使用 addPixmap() 时,您都会创建一个新的 QGraphicsPixmapItem,从而不必要地添加内存.解决方案是创建一个 QGraphicsPixmapItem 并重用它.另外处理任务会阻塞主线程,所以必须使用线程来完成繁重的任务,并通过信号发送QImage.
Every time you use addPixmap() you are creating a new QGraphicsPixmapItem adding memory unnecessarily. The solution is to create a QGraphicsPixmapItem and reuse it. In addition the processing task can block the main thread so you must use a thread to do the heavy task and send the QImage through signals.
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_())