如何在Python和OpenGL中使用glReadPixels?

时间:2018-09-01 07:51:28

标签: python python-3.x opengl pyopengl glreadpixels

如何使用glReadPixels()获得像素颜色的值?我做了很多尝试,但是得到了错误的价值。

我的背景色是blue(0,1,1),我绘制了一个边界颜色为red(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 :(得分:2)

您正在使用正交投影,该投影将坐标投影为(0,0)(640,640)的矩形形式:

gluOrtho2D(0.0,640.0,0.0,640.0)

但是您的窗口大小是(600,600)

glutInitWindowSize(600,600)

这将导致(0,0)(640,640)范围内的坐标从(0,0 )(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序列开始绘制以来已有数年的历史了。 阅读有关Fixed Function Pipeline的信息,并参阅Vertex SpecificationShader了解最新的渲染方式。

无论如何,我建议使用双缓冲

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()

答案 1 :(得分:1)

您的代码有几个问题。

  • 您的窗口大小与您在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版本。