Search code examples
pythonopenglglutpyopenglopengl-compat

Get ColorData from OpenGL use glReadPixels


I try to use boundary fill algorithm in pyopengl.

But when i want to get the color of triangle ,it does not work well.

It just get the background color,not the triangle`s color

You can see it in myDisplay() func.i`ve draw the triangle in color blue

    glBegin(GL_LINE_LOOP)
    glVertex2i(100, 100)
    glVertex2i(150, 100)
    glVertex2i(150, 150)

But i can not get the color of it.

At the same time,i draw a line to test,but i also can`t the color of it.

    for i in range(120, 130):
        setPixel(i, 110)
        print(i, 110, getColor(i, 110))
        print(i, 110, getColor(i, 111))
        print(i, 110, getColor(i, 109))

here`s the func of getcolor

def getColor(x, y):
    color = (GLuint * 1)(0)
    #读取点(x,y)的颜色color
    glReadPixels(122, 101, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, color)
    color=int(color[0])
    r = color & 255
    g = (color >> 8) & 255
    b = (color >> 16) & 255
    color = (r, g, b)
    return color

here`s the code

# -*- coding:utf-8 -*-
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *


#判断c1,c2的颜色是否相同
def rgbColorEqual(c1, c2):
    # if (abs(c1[0]-c2[0]) < 0.001 and abs(c1[1], c2[1]) < 0.001 and abs(c1[2]-c2[2]) < 0.001):
    #     return 1
    # else:
    #     return 0
    return 1
#绘制像素点(x,y)
def setPixel(x, y):
    glBegin(GL_POINTS)
    glVertex2i(x, y)
    glEnd()
    glFlush()
    return
#获得点(x,y)的颜色
def getColor(x, y):
    color = (GLuint * 1)(0)
    #读取点(x,y)的颜色color
    glReadPixels(122, 101, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, color)
    color=int(color[0])
    r = color & 255
    g = (color >> 8) & 255
    b = (color >> 16) & 255
    color = (r, g, b)
    return color
#4-连通边界填充算法
def boundaryFill4(x, y, fillColor, borderColor):
    interiorColor=getColor(x,y)
    print(x,y,interiorColor)
    # if(not rgbColorEqual(interiorColor, borderColor) and not rgbColorEqual(interiorColor, fillColor)):
    #     setPixel(x, y)
    # boundaryFill4(x+1,y,fillColor,borderColor)
    # boundaryFill4(x-1,y,fillColor,borderColor)
    # boundaryFill4(x,y+1,fillColor,borderColor)
    # boundaryFill4(x,y-1,fillColor,borderColor)

#显示函数
def myDisplay():
    glClear(GL_COLOR_BUFFER_BIT)
    #设置填充色为a红色
    #设置边界色为b蓝色
    a = (1, 0, 0)
    b = (0, 0, 1)
    glColor3fv(b)
    #绘制三角形的边
    glBegin(GL_LINE_LOOP)
    glVertex2i(100, 100)
    glVertex2i(150, 100)
    glVertex2i(150, 150)
    glEnd()
    glFlush()
    #取图形中的一点,进行填充
    glColor3fv(a)
    for i in range(120, 130):
        setPixel(i, 110)
        print(i, 110, getColor(i, 110))
        print(i, 110, getColor(i, 111))
        print(i, 110, getColor(i, 109))
    for i in range(100,150):
        print(i,100,getColor(i,100))
    boundaryFill4(120, 106, a, b)


if __name__ == "__main__":
    glutInit()
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE)
    glutInitWindowPosition(100, 100)
    glutInitWindowSize(500, 500)
    glutCreateWindow('midpointcircle')
    glClearColor(0.5, 0.5, 0.5, 0)
    glMatrixMode(GL_PROJECTION)
    gluOrtho2D(0.0, 500.0, 0.0, 500.0)
    glutDisplayFunc(myDisplay)
    glutMainLoop()

Solution

  • Ensure that the point and line primitives are draw at the center of the pixels. SInce the vertices are transformed by the projection matrix (and model view matrix) they may occur inaccuracies if you specify the vertices by integral coordinates:

    glBegin(GL_LINE_LOOP)
    glVertex2f(100+0.5, 100+0.5)
    glVertex2f(150+0.5, 100+0.5)
    glVertex2f(150+0.5, 150+0.5)
    glEnd()
    

    Of course you have to use the x and y coordinate in getColor;

    glReadPixels(122, 101, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, color)

    glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, color)
    

    Tuples are comparable, thus the implementation of rgbColorEqual is easy:

    def rgbColorEqual(c1, c2):
        return c1[0] == c2[0]
    

    You have to setPixel and continue the recursive algorithm, if interiorColor is not equal borderColor and not equal fillColor:

    def boundaryFill4(x, y, fillColor, borderColor):
        interiorColor=getColor(x,y)
        if not rgbColorEqual(interiorColor, borderColor) and not rgbColorEqual(interiorColor, fillColor):
            setPixel(x, y)
            boundaryFill4(x+1,y,fillColor,borderColor)
            boundaryFill4(x-1,y,fillColor,borderColor)
            boundaryFill4(x,y+1,fillColor,borderColor)
            boundaryFill4(x,y-1,fillColor,borderColor)
    

    The color channels which are returned by getColor are in range [0, 255]. I recommend to set the color attribute by values in the same range (glColor3ubv):

    def myDisplay():
        glClear(GL_COLOR_BUFFER_BIT)
        #设置填充色为a红色
        #设置边界色为b蓝色
        a = (255, 0, 0)
        b = (0, 0, 255)
        glColor3ubv(b)
        #绘制三角形的边
        glBegin(GL_LINE_LOOP)
        glVertex2f(100+0.5, 100+0.5)
        glVertex2f(150+0.5, 100+0.5)
        glVertex2f(150+0.5, 150+0.5)
        glEnd()
        glFlush()
        #取图形中的一点,进行填充
        glColor3ubv(a)
        boundaryFill4(120, 106, a, b)
        glFlush()
    

    See the example:

    # -*- coding:utf-8 -*-
    from OpenGL.GL import *
    from OpenGL.GLU import *
    from OpenGL.GLUT import *
    
    #判断c1,c2的颜色是否相同
    def rgbColorEqual(c1, c2):
        return c1[0] == c2[0]
    #绘制像素点(x,y)
    def setPixel(x, y):
        glBegin(GL_POINTS)
        glVertex2f(x+0.5, y+0.5)
        glEnd()
        glFlush()
        return
    #获得点(x,y)的颜色
    def getColor(x, y):
        color = (GLuint * 1)(0)
        #读取点(x,y)的颜色color
        glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, color)
        color=int(color[0])
        r = color & 255
        g = (color >> 8) & 255
        b = (color >> 16) & 255
        color = (r, g, b)
        return color
    #4-连通边界填充算法
    def boundaryFill4(x, y, fillColor, borderColor):
        interiorColor=getColor(x,y)
        if not rgbColorEqual(interiorColor, borderColor) and not rgbColorEqual(interiorColor, fillColor):
            setPixel(x, y)
            boundaryFill4(x+1,y,fillColor,borderColor)
            boundaryFill4(x-1,y,fillColor,borderColor)
            boundaryFill4(x,y+1,fillColor,borderColor)
            boundaryFill4(x,y-1,fillColor,borderColor)
        glFlush()
    
    #显示函数
    def myDisplay():
        glClear(GL_COLOR_BUFFER_BIT)
        #设置填充色为a红色
        #设置边界色为b蓝色
        a = (255, 0, 0)
        b = (0, 0, 255)
        glColor3ubv(b)
        #绘制三角形的边
        glBegin(GL_LINE_LOOP)
        glVertex2f(100+0.5, 100+0.5)
        glVertex2f(150+0.5, 100+0.5)
        glVertex2f(150+0.5, 150+0.5)
        glEnd()
        glFlush()
        #取图形中的一点,进行填充
        glColor3ubv(a)
        boundaryFill4(120, 106, a, b)
        glFlush()
    
    
    if __name__ == "__main__":
        glutInit()
        glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE)
        glutInitWindowPosition(100, 100)
        glutInitWindowSize(500, 500)
        glutCreateWindow('midpointcircle')
        glClearColor(0.5, 0.5, 0.5, 0)
        glMatrixMode(GL_PROJECTION)
        gluOrtho2D(0.0, 500.0, 0.0, 500.0)
        glutDisplayFunc(myDisplay)
        glutMainLoop()