Ошибка сегментации при рисовании кадра с веб-камеры в DrawableArea в pygtk3

Как следует из названия, я читаю кадры со своей веб-камеры (используя openCV, я хочу выполнить с ней некоторое обнаружение дополнительных функций) и хочу записать результат в виджет pyGTK3 DrawableArea. После этого ответа, который я процитирую для удобства:

Следующее, похоже, выполняет эту работу:

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

Остается один вопрос: является ли это предпочтительным способом ведения дел?

Итак, я сейчас использую:

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 - это пустой массив формы (m,n,3).

К сожалению, я получаю segmentation fault в заявлении:

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

Очевидно, это произошло с большим количеством участников, как видно из комментариев к приведенному выше ответу, однако решение не было предоставлено, и быстрый поиск в Google не дал результатов.

Обновление 1: загрузка pixbuf из файла работает должным образом, т.е.

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

с тем же вызовом _on_drawablearea_draw, за исключением изменения на ._image2pixbuf, отлично отображает some_test_image.jpg в виджете DrawableArea.

Обновление 2: преобразование в байты и создание pixbuf из байтов работает для меня, т.е.

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)

но он добавляет «ненужный» (?) Дополнительный шаг преобразования данных кадра в байты.

Вопросы:

  1. Как исправить эту ошибку сегментации в случае GdkPixbuf.Pixbuf.new_from_data? Сейчас мне кажется, что аргументы функции подобраны неудачно.

  2. Кроме того, поскольку приведенный выше ответ также спрашивает: является ли это предпочтительным способом записи кадра с веб-камеры в виджет DrawableArea?


person nluigi    schedule 30.10.2016    source источник


Ответы (1)


Чтобы ответить на ваш первый вопрос, проблема в том, что new_from_data() не делает копию данных изображения, которые вы ему передаете, он использует их напрямую, и в вашем случае данные изображения содержатся в frame_in_bytes переменная, которая является локальной для функции _frame2pixbuf. Таким образом, эти данные изображения, скорее всего, будут освобождены и перестанут быть действительными, как только вы выйдете за пределы области действия функции _frame2pixbuf.

Это не тот случай, когда вы используете функцию new_from_file, которая сама выделяет память изображения; ни в случае new_from_bytes, потому что вы создаете новый объект Bytes в куче, который не освобождается, когда вы покидаете область действия функции.

Чтобы использовать new_from_data(), вам нужно убедиться, что ваши данные изображения не станут недействительными до вызова Gdk.cairo_set_source_pixbuf(). Я думаю, что один из способов сделать это — поместить содержимое вашей функции _frame2pixbuf в вашу функцию _on_drawablearea_draw, чтобы переменная frame_in_bytes оставалась действительной в этом контексте.

person Stepan    schedule 10.01.2017