[英]QImage memory leak
I've written a OpenCV application which basically grabs frames from a camera, does some image processing and displays the image in two edited variants. 我编写了一个OpenCV应用程序,它基本上从相机中抓取帧,进行一些图像处理并以两种编辑的变体显示图像。 First, I've used
cv2.imshow()
to display the images, but while OpenCV (Build without Qt support) isn't able to provide modern GUI elements, I decided to use PySide
for my GUI. 首先,我使用
cv2.imshow()
来显示图像,但是当OpenCV(没有Qt支持的Build)无法提供现代GUI元素时,我决定将PySide
用于我的GUI。
But since this I get this error after processing about 830-850 frames (no matter, what timer rate I use, or how much image processing I do): 但是因为我在处理了大约830-850帧之后得到了这个错误(无论我使用什么计时器速率,或者我做了多少图像处理):
QImage: out of memory, returning null image
for both of my image views in the GUI, and then in each loop this one: 对于我在GUI中的两个图像视图,然后在每个循环中这个:
OpenCV Error: Unspecified error (The numpy array of typenum=2, ndims=3 can not be created) in NumpyAllocator::allocate, file ..\..\..\opencv-3.1.0\modules\python\src2\cv2.cpp, line 184
OpenCV Error: Insufficient memory (Failed to allocate 921600 bytes) in cv::OutOfMemoryError, file ..\..\..\opencv-3.1.0\modules\core\src\alloc.cpp, line 52
Traceback (most recent call last):
File "C:/myfile.py", line 140, in process_frame
img = QtGui.QImage(cv2.cvtColor(thresh_img, cv2.COLOR_RGB2BGR), self.width, self.height,
cv2.error: ..\..\..\opencv-3.1.0\modules\core\src\alloc.cpp:52: error: (-4) Failed to allocate 921600 bytes in function cv::OutOfMemoryError
Here's a part of my code (without image processing, but it also produces the error): 这是我的代码的一部分(没有图像处理,但它也产生错误):
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_())
In the Windows task manager I can see the RAM usage of my program: 在Windows任务管理器中,我可以看到我的程序的RAM使用情况:
At the point of crash, the app uses about 1.5 GB of RAM. 在崩溃时,该应用程序使用大约1.5 GB的RAM。 I've tried using the
gc
module and gc.collect()
after del img
, no success. 我尝试在
del img
之后使用gc
模块和gc.collect()
,但没有成功。
What else can I do? 我还可以做些什么?
EDIT: 编辑:
The threaded Camera
class doesn't matter here, the error does also appear without it. 线程
Camera
类在这里没关系,错误也会在没有它的情况下出现。
It seems to be a PySide specific bug, using PyQt will fix it. 它似乎是一个PySide特定的bug,使用PyQt会修复它。 It's not even OpenCV related.
它甚至与OpenCV无关。 It doesn't look like there will be a solution for using PySide right now...
现在看起来不会有使用PySide的解决方案......
Apparently this bug is due to garbage collection issues when using python 3.x 显然这个错误是由于使用python 3.x时的垃圾收集问题
A simple workaround using ctypes has been provided here https://bugreports.qt.io/browse/PYSIDE-140 and https://github.com/matplotlib/matplotlib/issues/4283#issuecomment-92773487 这里提供了一个使用ctypes的简单解决方法https://bugreports.qt.io/browse/PYSIDE-140和https://github.com/matplotlib/matplotlib/issues/4283#issuecomment-92773487
On the last link see the post "mfitzp commented on Apr 24, 2015". 在最后一个链接上看到帖子“mfitzp评论于2015年4月24日”。 This worked for me!
这对我有用!
In my case, I was using QStackedWidget
for switching between different views and QTimer
to trigger the view switch (on certain conditions). 在我的例子中,我使用
QStackedWidget
在不同视图和QTimer
之间切换以触发视图切换(在某些条件下)。
I was using functools.partial
for passing arguments from one view to another, among which I did pass instances, such as PIL.Image
, QImage
, ImageQt
and QPixmap
. 我使用
functools.partial
将参数从一个视图传递到另一个视图,其中我确实传递了实例,例如PIL.Image
, QImage
, ImageQt
和QPixmap
。
That's where it went wrong. 那是它出错的地方。 When such resources are passed from one view to another, they are not being cleaned well by the garbage collector.
当这些资源从一个视图传递到另一个视图时,垃圾收集器不能很好地清理它们。
What worked for me. 什么对我有用。
Declare all variables that you plan to pass from one view to another as class properties (in the constructor of your QWidget
). 将您计划从一个视图传递到另一个视图的所有变量声明为类属性(在
QWidget
的构造函数中)。 Store all image resources (such as PIL.Image
, QImage
, ImageQt
and QPixmap
) in those variables/properties. 将所有图像资源(例如
PIL.Image
, QImage
, ImageQt
和QPixmap
)存储在这些变量/属性中。
Don't pass any arguments (containing image resources) from one view to another. 不要将任何参数(包含图像资源)从一个视图传递到另一个视图。
Additionally if you're using PyQT with OpenCV, note that OpenCV 2.9 contains a bug, which causes memory leak. 另外,如果您在OpenCV中使用PyQT,请注意OpenCV 2.9包含一个错误,导致内存泄漏。 Make sure to upgrade to latest version (either latest 2.x or 3.x) before you spend hours on finding out where the memory leaks come from.
确保在花费数小时查找内存泄漏的来源之前升级到最新版本(最新的2.x或3.x)。
Look at my comment at PYSIDE-140: https://bugreports.qt.io/browse/PYSIDE-140 看看我对PYSIDE-140的评论: https ://bugreports.qt.io/browse/PYSIDE-140
Avoiding mixing python objects with Qt objects. 避免将python对象与Qt对象混合。 Try example below and avoid playing with refcounts fixing.
尝试下面的示例,避免使用refcounts修复。
stream = cv2.VideoCapture(0)
grabbed, frame = stream.read()
height, width = frame.shape[:2]
data = Qt.QByteArray(cv2.cvtColor(frame, cv2.COLOR_RGB2BGR).tostring())
qimg = Qt.QImage(data, width, height, Qt.QImage.Format_RGB888)
data.clear()
del data
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.