2015-06-03 29 views
2

我正在嘗試創建一個Gtk Widget,您可以將OpenCV圖像傳遞給它,然後顯示它。我創建了一個從Gtk.Image繼承的類,用於顯示圖像。您使用show_frame方法將OpenCV圖像傳遞給此類,然後更新Gtk.Image以顯示該圖像。當在Gtk Widget中顯示OpenCV圖像時發生內存泄露

我已經測試過它,它工作正常,即在調用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

你有沒有嘗試unf'pixbuf'? (免責聲明:不確定它是否能正常工作。) – ace

+0

@ace嘗試使用pixbuf.unref()來取消映射'pixbuf'引發'RuntimeError:此方法當前不受支持。 – mpursuit

+0

在這裏有同樣的,你找到一個解決方案? – Bigfoot

回答

0

從PyGTK的常見問題摘錄,section 5.17

There is a reference cycle between the python wrapper and its underlying C object; this means that the object will not be automatically deallocated when there are no more user references, and you will need the garbage collector to kick in (which may take a few cycles). This occasionally causes the odd problem, such as with pixbufs described in FAQ 8.4

而且從section 8.4

The answer is "Interesting GC behaviour" in Python. Apparently finalizers are not necessarily called as soon as an object goes out of scope. My guess is that the python memory manager doesn't directly know about the storage allocated for the image buffer (since it's allocated by the gdk) and that it therefore doesn't know how fast memory is being consumed. The solution is to call gc.collect() at some appropriate place.

For example, I had some code that looked like this:

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) 

This chewed up an unacceptably large amount of memory for any reasonable image set. Changing the code to look like this fixed the problem:

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),但我相信這是解決這個問題的方法。

+0

我試圖通過在函數的末尾添加'del pixbuf'和'gc.collect()'來達到這個目的,但是這並不能阻止內存使用的增加。 – mpursuit

3

好,

我找到了解決辦法,但我不明白爲什麼它的工作原理:與pixbuffer的副本設置圖像。

imageWidget.set_from_pixbuf(pixbuffer.copy()) 

我來到這個溶液觀察到內存泄漏disapeared用於縮放pixbuffers(即pixbuffer.scale_simple結果)後。

+0

這確實保持了內存使用情況!你覺得這樣做有很大的表現嗎?基本上我們正在創建兩個像素緩衝器。 – nluigi

相關問題