奇幻记忆

2024-09-14 23:10:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经编写了一个OpenCV应用程序,它基本上从相机抓取帧,进行一些图像处理,并以两种编辑过的变体显示图像。首先,我使用了cv2.imshow()来显示图像,但是尽管OpenCV(不支持Qt的构建)不能提供现代的GUI元素,但是我决定使用PySide作为我的GUI。在

但由于这一点,我在处理大约830-850帧后会出现这个错误(不管我使用什么定时器速率,也不管我做了多少图像处理):

QImage: out of memory, returning null image

对于图形用户界面中的两个图像视图,然后在每个循环中都执行以下操作:

^{pr2}$

以下是我的部分代码(没有图像处理,但也会产生错误):

import cv2
import sys
from PySide import QtGui, QtCore
from threading import Thread


class MainWindow(QtGui.QMainWindow):
    def __init__(self, cam=0, parent=None):
        super(MainWindow, self).__init__(parent)

        self.camera = Camera(cam).start()
        self.title = "Cam %s" % cam
        self.counter = 0

        widget = QtGui.QWidget()
        self.layout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight)

        self.video_frame = QtGui.QLabel()
        self.thresh_frame = QtGui.QLabel()

        self.layout.addWidget(self.video_frame)
        self.layout.addWidget(self.thresh_frame)
        self.layout.addStretch()

        self.setCentralWidget(widget)
        widget.setLayout(self.layout)

        self.setMinimumSize(640, 480)
        self._timer = QtCore.QTimer(self)
        self._timer.timeout.connect(self.process_frame)
        self._timer.start(20)

    def process_frame(self):
        self.counter += 1
        print(self.counter)
        self.frame = self.camera.read()
        self.height, self.width = self.frame.shape[:2]

        thresh_img = cv2.threshold(cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY), 0, 255,
                                   cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
        thresh_img = cv2.erode(thresh_img, None, iterations=2)
        thresh_img = cv2.dilate(thresh_img, None, iterations=2)
        thresh_img = cv2.cvtColor(thresh_img, cv2.COLOR_GRAY2RGB)

        img = QtGui.QImage(cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR), self.width, self.height,
                           QtGui.QImage.Format_RGB888)
        img = QtGui.QPixmap.fromImage(img)
        self.video_frame.setPixmap(img)

        img = QtGui.QImage(cv2.cvtColor(thresh_img, cv2.COLOR_RGB2BGR), self.width, self.height,
                           QtGui.QImage.Format_RGB888)
        img = QtGui.QPixmap.fromImage(img)
        self.thresh_frame.setPixmap(img)

    def closeEvent(self, event):
        self.camera.stop()
        event.accept()


class Camera:
    def __init__(self, src=0):
        self.stream = cv2.VideoCapture(src)
        (self.grabbed, self.frame) = self.stream.read()

        self.stopped = False

    def start(self):
        Thread(target=self.update, args=()).start()
        return self

    def update(self):
        while True:
            if self.stopped:
                return
            (self.grabbed, self.frame) = self.stream.read()

    def read(self):
        return self.frame

    def stop(self):
        self.stopped = True

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow(0)
    window.show()
    sys.exit(app.exec_())

在Windows任务管理器中,我可以看到程序的RAM使用情况:

enter image description here

在崩溃点,应用程序使用大约1.5GB的RAM。我尝试过使用gc模块和gc.collect()后的del img,但没有成功。在

我还能做什么?在

编辑:

threadedCamera类在这里无关紧要,没有它也会出现错误。在


Tags: importselfimgreaddefcv2framestart
3条回答

在我的例子中,我使用QStackedWidget在不同的视图之间切换,QTimer来触发视图切换(在某些情况下)。在

我使用functools.partial将参数从一个视图传递到另一个视图,其中我传递了实例,例如PIL.ImageQImageImageQt和{}。在

这就是问题所在。当这些资源从一个视图传递到另一个视图时,垃圾回收器不会很好地清理它们。在

对我有用。在

  1. 将计划从一个视图传递到另一个视图的所有变量声明为类属性(在QWidget的构造函数中)。将所有图像资源(例如PIL.ImageQImageImageQt和{})存储在这些变量/属性中。

  2. 不要将任何参数(包含图像资源)从一个视图传递到另一个视图。


另外,如果在OpenCV中使用PyQT,请注意opencv2.9包含一个bug,它会导致内存泄漏。在花费数小时找出内存泄漏的来源之前,请确保升级到最新版本(最新的2.x或3.x)。在

这似乎是一个PySide特有的bug,使用PyQt可以修复它。它甚至与OpenCV无关。现在看来还没有一个使用PySide的解决方案。。。在

显然,这个bug是由于使用python3.x时的垃圾回收问题造成的

这里提供了一个使用ctypes的简单解决方案https://bugreports.qt.io/browse/PYSIDE-140https://github.com/matplotlib/matplotlib/issues/4283#issuecomment-92773487

最后一个链接见帖子“mfitzp于2015年4月24日发表评论”。这对我有用!在

相关问题 更多 >