Segmentation fault while drawing frame from webcam to DrawableArea in pygtk3
Asked Answered
L

1

1

As title suggests I am reading frames from my webcam (using openCV, i want to do some follow up feature detection with it) and want to write the result to a pyGTK3 DrawableArea widget. Following this answer, which i will quote for convenience:

The following seems to do the job:

def draw(self, widget, context):
    Gdk.cairo_set_source_pixbuf(context, self.pixbuf, 0, 0)
    context.paint()

One question still remains: Is this the preferred way of doing things?

So i am now using:

def _on_drawablearea_draw(self, canvas, context):
    frame = self.stream.read()
    self.pixbuf = self._frame2pixbuf(frame)
    Gdk.cairo_set_source_pixbuf(context, self.pixbuf, 0, 0)
    context.paint()

def _frame2pixbuf(self, frame):
    height, width, rgb_stride = frame.shape
    frame_to_list = frame.flatten() # must become list
    return GdkPixbuf.Pixbuf.new_from_data(frame_to_list,
                                          GdkPixbuf.Colorspace.RGB,
                                          False, 8, 
                                          width, height, rgb_stride * width)

frame is a numpy array of shape (m,n,3).

Unfortunately, I get a segmentation fault at the statement:

Gdk.cairo_set_source_pixbuf(context, self.pixbuf, 0, 0)

This apparantly happened to more members as seen in the comments to the above quoted answer, however no solution was provided and a quick google search yields no results.

Update 1: Loading pixbuf from file is working as expected, i.e.

def _image2pixbuf(self):
    filename = 'some_test_image.jpg'
    return GdkPixbuf.Pixbuf.new_from_file(filename)

with the same call to _on_drawablearea_draw except for the change to ._image2pixbuf renders some_test_image.jpg perfectly in the DrawableArea widget.

Update 2: Converting to bytes and creating the pixbuf from bytes works for me, i.e.

def _frame2pixbuf(self, frame):
    height, width, rgb_stride = frame.shape
    frame_in_bytes = GLib.Bytes.new(frame.tobytes())
    return GdkPixbuf.Pixbuf.new_from_bytes(frame_in_bytes,
                                          GdkPixbuf.Colorspace.RGB,
                                          False, 8, 
                                          width, height, rgb_stride * width)

but it adds an 'unnecessary' (?) additional step of converting the frame data to bytes.

Questions:

  1. How do i fix this segmentation fault in the case of GdkPixbuf.Pixbuf.new_from_data? It seems to me now that the arguments to the function are badly chosen.

  2. Furthermore, as the above quoted answer also asks: is this the preferred way of writing a frame from a webcam to a DrawableArea widget?

Leaseholder answered 30/10, 2016 at 7:45 Comment(0)
E
0

To answer your first question, the issue is that new_from_data() does not make a copy of the image data that you pass to it, it uses it directly and in your case the image data is contained in the frame_in_bytes variable which is local to the _frame2pixbuf function. Thus that image data is likely freed and is no longer valid once you're out of the _frame2pixbuf function scope.

This is not the case when you use the new_from_file function which allocates the image memory itself; nor in the case of new_from_bytes because you create a new Bytes object on the heap which does not get freed when you leave the function scope.

To use new_from_data(), you would have to make sure that your image data does not become invalid before Gdk.cairo_set_source_pixbuf() is called. I think one way to do that would be to put the contents of your _frame2pixbuf function into your _on_drawablearea_draw function so that the frame_in_bytes var remains valid in that context.

Elburr answered 10/1, 2017 at 21:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.