Как использовать glReadPixels в Python и OpenGL? - PullRequest
0 голосов
/ 01 сентября 2018

Как я могу получить значение цвета пикселя, используя glReadPixels ()? Я сделал так много попыток, но получил неправильное значение.

Мой цвет фона синий (0,1,1), и я нарисовал круг с красным цветом границы (1,0,0), и я хочу получить цвет любой граничной точки. Так что это должно дать мне красный. но я получаю цвет фона.

Вот мой код на Python3 и OpenGL

from OpenGL.GLU import *
from OpenGL.GLUT import *
import time
from  math import *
import numpy
import sys

def init():

    glClearColor(0.0,1.0,1.0,0.0)
    glClear(GL_COLOR_BUFFER_BIT)
    glPointSize(3.0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0.0,640.0,0.0,640.0)

def circle():

    for i in range(361):
        m=float(50*cos(i*pi/180.0))+320
        n=float(50*sin(i*pi/180.0))+320
        setpixc(m,n)

    print(m,n)
    redinput()

def redinput():

    global x,y
    x=int(input("enter x:"))
    y=int(input("enter y:"))
    setpixc(x,y)
    pixel=[]
    c=glReadPixels(x,y,1.0,1.0,GL_RGB,GL_UNSIGNED_BYTE,None)
    print(c)
    string_pixels=numpy_pixel.tolist()
    print(string_pixels)

def setpixc(xcor,ycor):

    glBegin(GL_POINTS)
    glColor3f(1.0,0.0,0.0)
    glVertex2f(xcor,ycor)
    glEnd()
    glFlush()

def Display():

    circle()
    print("hello")

def main():

    glutInit(sys.argv)

    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(600,600)
    glutInitWindowPosition(10,10)
    glutCreateWindow("line-dda")

    glutDisplayFunc(Display)

    init()
    glutMainLoop()

main()

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Есть несколько проблем с вашим кодом.

  • ваш размер окна отличается от данных, которые вы используете в gluOrtho2D
  • вы полагаетесь на точечную растеризацию пикселей, а OpenGL не гарантирует это.

Ответ, который вы ищете, описан в «Красной книге» (т. Е. В Руководстве по программированию OpenGL), в частности в Приложение G, Советы по программированию . Я бы также предложил вам прочитать Приложение H, Инвариантность . Онлайн-версию можно найти по следующей ссылке: https://www.glprogramming.com/red/

Также

  • вам не нужно вызывать glFlush после каждой нарисованной точки, вызывайте ее один раз перед тем, как glReadPixels ...
  • вы используете пару glBegin / glEnd для каждой точки, что является огромной тратой Ресурсы. Вы можете нарисовать полный круг, используя одну пару glBegin / glEnd:

    glBegin(GL_POINTS)
    glColor3f(1.0, 0.0, 0.0)
    for i in range(361):
        x=float(50*cos(i*pi/180.0))+320
        y=float(50*sin(i*pi/180.0))+320
        glVertex2f(x,y)
    glEnd()
    
  • вы используете очень плотный набор GL_POINTS для рисования круга, но это не будет способствовать правильному окружению. Если радиус меньше, у вас будет многократная растеризация одного и того же пикселя окна. Если вы достаточно увеличите радиус, это приведет к множеству несвязанных точек. В вашей ситуации я бы использовал GL_LINE_LOOP:

    glBegin(GL_LINE_LOOP)
    glColor3f(1.0, 0.0, 0.0)
    for i in range(0, 360, 5):
        x=float(50*cos(i*pi/180.0))+320
        y=float(50*sin(i*pi/180.0))+320
        glVertex2f(x,y)
    glEnd()
    
  • И последнее, но не менее важное: это древний способ использования OpenGL. Если у вас нет веских причин, я бы предложил перейти на более новую версию OpenGL.

0 голосов
/ 01 сентября 2018

Вы используете ортогональную проекцию, которая проецирует координаты в прямоугольную форму (0, 0) до (640, 640) :

gluOrtho2D(0.0,640.0,0.0,640.0)

Но ваш размер окна (600, 600) :

glutInitWindowSize(600,600)

Это приводит к тому, что координаты в диапазоне от (0, 0) до (640, 640) отображаются в области просмотра из (0, 0) * От 1018 * до (600, 600) , glVertex2f:

Но когда координаты читаются как glReadPixels, вам придется использовать координаты области просмотра (в пикселях).

Чтобы решить эту проблему, вы можете изменить размер окна с (600, 600) на (640, 640) :

glutInitWindowSize(640, 640)

Теперь, например.

x=270
y=320

вернет красный пиксель.


Обратите внимание: если вы не хотите изменять размер окна, вам придется масштабировать входные координаты на 600/640 .

scale = 600/640
c=glReadPixels(x*scale,y*scale,1.0,1.0,GL_RGB,GL_UNSIGNED_BYTE,None)

например.

x = 270 * 600 / 640 = 253
y = 320 * 600 / 640 = 300 

Далее отметим, что рисование последовательностями glBegin / glEnd считается устаревшим в течение нескольких лет. Прочтите о конвейере с фиксированными функциями и посмотрите Вершинные спецификации и Шейдер для современного способа рендеринга.

В любом случае, я рекомендую использовать двойную буферизацию

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)

и сделать один обмен буферов после того, как весь круг был нарисован. Пропустите вызов glFlush в setpixc и добавьте одиночный вызов glutSwapBuffers к функции Display и не забудьте очистить экран перед рендерингом:

def Display():

    glClear(GL_COLOR_BUFFER_BIT)
    circle()

    glutSwapBuffers()
    glutPostRedisplay()

    redinput()
    print("hello")

Вам решать, хотите ли вы нарисовать круг отдельными точками

def circle():
    glPointSize(3.0)
    glColor3f(1.0,0.0,0.0)
    glBegin(GL_POINTS)
    for i in range(360):
        m=float(50*cos(i*pi/180.0))+320
        n=float(50*sin(i*pi/180.0))+320
        glVertex2f(m,n)
    glEnd()

или связная линия:

def circle():
    glLineWidth(3.0)
    glColor3f(1.0,0.0,0.0)
    glBegin(GL_LINE_LOOP)
    for i in range(360):
        m=float(50*cos(i*pi/180.0))+320
        n=float(50*sin(i*pi/180.0))+320
        glVertex2f(m,n)
    glEnd()

Если вы хотите получить цвет пикселя щелчком мыши, вы можете установить обратный вызов мыши с помощью glutMouseFunc:

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from math import *

def init():
    global width, height

    glClearColor(0.0, 1.0, 1.0, 0.0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0.0, width, 0.0, height)

def circle():
    glLineWidth(3.0)
    glColor3f(1.0, 0.0, 0.0)
    glBegin(GL_LINE_LOOP)
    for i in range(360):
        m=float(50*cos(i*pi/180.0))+320
        n=float(50*sin(i*pi/180.0))+320
        glVertex2f(m, n)
    glEnd()

def Mouse(button, state, x, y):
    global mouse_x, mouse_y, get_input

    if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        mouse_x = x
        mouse_y = height - y # the y coordinate of the mouse has to be flipped
        get_input = True

def redinput(x, y):
    c = glReadPixels(x, y, 1.0, 1.0, GL_RGB,GL_UNSIGNED_BYTE, None)
    print(c)

def Display():
    global mouse_x, mouse_y, get_input

    glClear(GL_COLOR_BUFFER_BIT)
    circle()

    glutSwapBuffers()
    glutPostRedisplay()

    if get_input: 
        redinput(mouse_x, mouse_y)
        get_input=False

def main():
    global width, height

    glutInit(sys.argv)

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
    glutInitWindowSize(width, height)
    glutInitWindowPosition(10, 10)
    glutCreateWindow("line-dda")

    glutDisplayFunc(Display)
    glutMouseFunc(Mouse)

    init()
    glutMainLoop()

width   = 640
height  = 640
mouse_x = 0
mouse_y = 0
get_input = False
main()
...