问题
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:
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.Furthermore, as the above quoted answer also asks: is this the preferred way of writing a frame from a webcam to a DrawableArea widget?
回答1:
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.
来源:https://stackoverflow.com/questions/40327001/segmentation-fault-while-drawing-frame-from-webcam-to-drawablearea-in-pygtk3