Получить данные из OpenGL glReadPixels (используя Pyglet)

Я использую Pyglet (и OpenGL) в Python в приложении, я пытаюсь использовать glReadPixels для получения значений RGBA для набора пикселей. Насколько я понимаю, OpenGL возвращает данные в виде упакованных целых чисел, поскольку именно так они хранятся на оборудовании. Однако по понятным причинам я хотел бы привести его в нормальный формат для работы. Основываясь на некоторых чтениях, я придумал следующее: http://dpaste.com/99206/ , однако он терпит неудачу с IndexError. Как мне это сделать?


person Alex Gaynor    schedule 15.12.2008    source источник


Ответы (5)


Вы должны сначала создать массив правильного типа, а затем передать его в glReadPixels:

a = (GLuint * 1)(0)
glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_INT, a)

Чтобы проверить это, вставьте следующее в пример Pyglet «opengl.py»:

@window.event
def on_mouse_press(x, y, button, modifiers):
    a = (GLuint * 1)(0)
    glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_INT, a)
    print a[0]

Теперь вы должны видеть цветовой код пикселя под курсором мыши всякий раз, когда вы щелкаете где-нибудь в окне приложения.

person Deestan    schedule 08.02.2009
comment
Это отличный пример, хотя мне больше повезло определить a как GLubyte и использовать GL_UNSIGNED_BYTE. Если вы используете их, выбранный цвет вернется в виде значений от 0 до 255 вместо непонятных longs. - person Thane Brimhall; 21.11.2013

Вы можете использовать библиотеку PIL, вот фрагмент кода, который я использую для захвата такого изображения:

    buffer = gl.glReadPixels(0, 0, width, height, gl.GL_RGB, 
                             gl.GL_UNSIGNED_BYTE)
    image = Image.fromstring(mode="RGB", size=(width, height), 
                             data=buffer)
    image = image.transpose(Image.FLIP_TOP_BOTTOM)

Я предполагаю, что включение альфа-канала должно быть довольно простым (возможно, просто заменить RGB на RGBA, но я этого не пробовал).

Изменить: я не знал, что API-интерфейс pyglet OpenGL отличается от PyOpenGL. Я предполагаю, что нужно изменить приведенный выше код, чтобы использовать буфер в качестве седьмого аргумента (в соответствии с менее питоническим стилем pyglet).

person nikow    schedule 15.12.2008
comment
Когда я пытаюсь это сделать, я получаю ошибку типа, что glReadPixels принимает 7 аргументов, а не 6. - person Alex Gaynor; 15.12.2008
comment
Уверены ли вы? Я использовал этот код на разных машинах с разными версиями PyOpenGL. Может быть, это что-то конкретное для пиглета? Возможно, передайте переменную буфера в качестве седьмого аргумента. - person nikow; 15.12.2008

Я смог получить весь буфер кадра, используя glReadPixels(...), а затем использовал PIL для записи в файл:

# Capture image from the OpenGL buffer
buffer = ( GLubyte * (3*window.width*window.height) )(0)
glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, buffer)

# Use PIL to convert raw RGB buffer and flip the right way up
image = Image.fromstring(mode="RGB", size=(window.width, window.height), data=buffer)     
image = image.transpose(Image.FLIP_TOP_BOTTOM)

# Save image to disk
image.save('jpap.png')

Меня не интересовала альфа-версия, но я уверен, что вы могли бы легко добавить ее.

Я был вынужден использовать glReadPixels(...) вместо кода Pyglet

pyglet.image.get_buffer_manager().get_color_buffer().save('jpap.png')

потому что вывод с использованием save(...) не был идентичен тому, что я видел в окне. (Буферы мультисэмплинга пропущены?)

person jpap    schedule 08.11.2010

Если вы прочтете фрагмент кода, на который вы ссылаетесь, вы поймете, что самый простой способ получить «нормальные» значения — это просто получить доступ к массиву в правильном порядке.
Этот фрагмент выглядит так, как будто он должен выполнять свою работу. Если это не так, отладьте его и посмотрите, в чем проблема.

person shoosh    schedule 15.12.2008
comment
Ну, данные, которые возвращает glReadPixels, — это просто массив с n значениями, где n — количество пикселей в области. На самом деле я не уверен, что этот фрагмент имеет какой-то смысл, это более или менее объединение того, что я читал. - person Alex Gaynor; 15.12.2008

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

person Alex Gaynor    schedule 15.12.2008