python 3.x -在Gtk小部件中显示OpenCV图像时内存泄漏



我试图创建一个Gtk小部件,您可以通过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)

嗯,

我找到了一个解决方案,但我不明白为什么它工作:设置图像与pixbuffer的副本。

 imageWidget.set_from_pixbuf(pixbuffer.copy())

我来到这个解决方案后,观察到内存泄漏消失缩放像素缓冲区(即pixbuffer.scale_simple的结果)。

节选自PyGTK FAQ,第5.17节:

在python包装器和它的底层C对象之间有一个引用循环;这意味着当没有更多的用户引用时,对象将不会被自动释放,并且您将需要垃圾收集器启动(这可能需要几个周期)。这偶尔会导致一些奇怪的问题,比如FAQ 8.4

中描述的pixbufs。

和8.4节中的

答案是Python中的"有趣的GC行为"。显然,当对象超出作用域时,不一定会立即调用终结器。我的猜测是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),但我相信这是解决它的方法。

相关内容

  • 没有找到相关文章

最新更新