我正在尝试创建一个Gtk Widget,您可以将OpenCV
图像传递给它,然后显示它。我创建了一个继承自Gtk.Image
的类,用于显示图像。您使用show_frame
方法将OpenCV图像传递给此类,然后更新Gtk.Image
以显示该图像。
我已对此进行了测试并且工作正常,即在调用show_frame
方法时图像被正确显示和更新。但是每次更新图像时,使用的内存都会增加,直到内存不足并且程序崩溃。
我认为这是由于图像没有正确释放的内存。然而,我不知道如何解决这个问题。一旦收到新帧,我就尝试不引用gbytes
,但这没有帮助。内存仅在调用set_from_pixbuf
函数时建立。如果这被注释掉,则内存使用量保持不变。
class OpenCVImageViewer(Gtk.Image):
def __init__(self):
Gtk.Image.__init__(self)
def show_frame(self, frame):
# Convert to opencv BGR to Gtk RGB
rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Get details about frame in order to set up pixbuffer
height = rgb_image.shape[0]
width = rgb_image.shape[1]
nChannels = rgb_image.shape[2]
gbytes = GLib.Bytes.new(rgb_image.tostring())
pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(gbytes, GdkPixbuf.Colorspace.RGB, False,
8, width, height, width*nChannels)
# Add Gtk to main thread loop for thread safety
GLib.idle_add(self.set_from_pixbuf, pixbuf)
GLib.idle_add(self.queue_draw)
答案 0 :(得分:3)
那么,
我找到了一个解决方案,但我不明白它为什么会起作用:用pixbuffer的副本设置图像。
imageWidget.set_from_pixbuf(pixbuffer.copy())
在观察到缩放的pixbuffers(即pixbuffer.scale_simple
的结果)内存泄漏消失后,我找到了这个解决方案。
答案 1 :(得分:0)
摘自PyGTK常见问题解答,section 5.17:
python包装器与其底层C对象之间存在引用循环;这意味着当没有更多用户引用时,对象将不会被自动释放,并且您将需要垃圾回收器(这可能需要几个周期)。这偶尔会导致奇怪的问题,例如FAQ 8.4中描述的pixbufs
来自section 8.4:
答案是"有趣的GC行为"在Python中。显然,一旦对象超出范围,终结器就不一定被调用。我的猜测是python内存管理器并不直接知道为图像缓冲区分配的存储空间(因为它是由gdk分配的),因此它并不知道内存的存储速度有多快消耗。 解决方案是在适当的地方调用gc.collect()。
例如,我有一些看起来像这样的代码:
for image_path in images: pb = gtk.gdk.pixbuf_new_from_file(image_path) pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR) thumb_list_model.set_value(thumb_list_model.append(None), 0, pb)
这为任何合理的图像集咀嚼了无法接受的大量内存。将代码更改为这样可以解决问题:
import gc for image_path in images: pb = gtk.gdk.pixbuf_new_from_file(image_path) pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR) thumb_list_model.set_value(thumb_list_model.append(None), 0, pb) del pb gc.collect()
我不确定你应该在代码中调用垃圾收集器(因为我不太了解Python),但我相信这是解决问题的方法。