如何在Python和OpenGL中使用glReadPixels?

2024-09-25 14:24:28 发布

您现在位置:Python中文网/ 问答频道 /正文

如何使用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()

Tags: fromimportnumpyinit颜色defsysopengl
2条回答

您使用的是正交投影,它将坐标投影到矩形形式(0,0)(640,640)

gluOrtho2D(0.0,640.0,0.0,640.0)

但你的窗口大小是(600600)

^{pr2}$

这将导致从(0,0)(640,640)范围内的坐标绘制到从(0,0)(600,600)的视口中,方法是^{}

但是当^{}读取坐标时,您必须使用viewport(像素)坐标。在

要解决您的问题,您可以将窗口大小从(600600)更改为(640640640)

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)

在画出整个圆之后,进行一次缓冲区交换。跳过setpixc中的glFlush调用,并向Display函数添加一个glutSwapBuffers调用,并且不要忘记在呈现之前清除显示:

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

如果要通过鼠标单击获得像素的颜色,可以通过^{}设置鼠标回拨:

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

你的代码有几个问题。在

  • 窗口大小与GluOrthor2D中使用的数据不同
  • 您依赖于像素精确光栅化,而OpenGL不保证这一点。在

您正在搜索的答案在“红皮书”(即OpenGL编程指南)中描述,特别是在附录G,编程技巧中。我也建议你阅读附录H,不变性。在线版本可以在以下链接找到:https://www.glprogramming.com/red/

还有

  • 不需要每次都调用一次glpoint。。。在
  • 每个点都使用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_nu点来画圆,但这将不会产生正确的圆。如果半径较小,将对同一窗口像素进行多次光栅化。如果你增加足够的半径,它将导致一组不相连的点。在您的情况下,我会使用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版本。

相关问题 更多 >