2012-08-06 16 views
7

Necesito generar algunas series de imágenes de prueba para una aplicación fotogramétrica. Deben contener objetos simples (discos, rectángulos, etc.) con una posición muy precisa.Renderización de subpíxeles en OpenGL: problema de precisión

Considerando una imagen en escala de grises de 8 bits de un rectángulo negro sobre fondo blanco, un desplazamiento observable mínimo (después de la interpolación) debería ser de 1/256 píxeles, ya que hay 256 niveles de intensidad posibles de cada píxel.

decidí usar OpenGL (con Python + Pyglet) para hacer este tipo de imágenes, como más adelante voy a tener que hacer más complicados (3d escena, pares de imágenes estéreo)

Por desgracia, la mejor precisión que han logrado es alrededor de píxel/10, no se usa la profundidad de intensidad completa.

¿Es posible hacerlo mejor, idealmente, logrando una precisión total de 1/256 píxeles? ¿Alguna pista sobre cómo hacer eso, por favor?

código de ejemplo, la generación de imágenes de un disco parcial, se movió 0,01 pixel más en cada trama

#-*- coding: utf-8 -*- 
import pyglet 
from pyglet.gl import * 
from PIL import Image, ImageGrab 

config = pyglet.gl.Config(width = 800, height = 600, sample_buffers=1, samples=16) 
window = pyglet.window.Window(config=config, resizable=True) 
window.set_size(800, 600) 

printScreenNr = 0 

@window.event 
def on_draw(): 
    global printScreenNr 
    window.clear() 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glLoadIdentity() 
    glEnable(GL_LINE_SMOOTH) 
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 

    glTranslated(200, 200,0) 

    circleQuad = gluNewQuadric() 
    glTranslated(200+(printScreenNr*0.01), 0, 0) 
    gluPartialDisk(circleQuad, 0, 50, 500, 500, 0, 180) 

@window.event 
def on_resize(width, height): 
    glViewport(0, 0, width, height) 
    glMatrixMode(GL_PROJECTION) 
    glLoadIdentity() 
    glOrtho (0, width, height, 0, 0, 1); 
    glMatrixMode(GL_MODELVIEW) 
    return pyglet.event.EVENT_HANDLED 

@window.event 
def on_text(text): 
    global printScreenNr 
    if(text == "p"): 
     pyglet.image.get_buffer_manager().get_color_buffer().save('photo'+str(printScreenNr)+'.tiff') 
     printScreenNr += 1 

pyglet.app.run() 

(el código anterior está usando gluPartialDisk, pero He probado la cuestión también usando cuadrángulos, exactitud resultados hizo no difiere)

+0

¿Ha intentado utilizar una profundidad de color de 32 bits? La razón por la que digo esto es porque las rutas de 32 bits son las rutas de código más utilizadas y por lo tanto más mantenidas en los controladores de gráficos en la actualidad. Si esto funciona, puede realizar una nueva escala de profundidad de color de alta calidad después. – Ani

+0

intenté eso, pero no cambié los resultados ... todavía, gracias – Pietro

Respuesta

4

Una manera simple de hacer esto es escalar la imagen por un factor. Si escala la imagen por 4.0, entonces 16 píxeles originales se fusionarán en un píxel objetivo, lo que le otorga 16 tonos de gris al escalar una imagen pura B & W.

Pero hay una trampa que probablemente explica su problema. Si usted tiene esto:

...##### 
    ...##### 
    ...##### 
    ...##### 

(izquierda: blanco, derecha: negro rectángulo relleno), entonces usted tiene 12 en blanco y 4 píxeles negros que contribuyen a un solo píxel de salida. Para obtener 1 píxel negro, la entrada debería ser la siguiente:

....#### 
    ....#### 
    ....#### 
    ...##### 

Ver? Aunque la caja negra gotea solo un píxel en el espacio en blanco, lo hace cuatro veces. Por lo tanto, para asegurarse de que su código de representación subpixel funcione, debe mirar píxeles individuales o esquinas, no en los bordes.

+0

Renderizar una imagen (de manera) más grande sería una solución, pero creo que el tamaño de la pantalla es una limitación? Por lo tanto, no será de mucha ayuda Acerca de la otra parte de su respuesta, no estoy seguro si entiendo correctamente ... si la imagen ha sido escalada 4x (en cada dirección), que da 4 posibles sombras al observar un borde (y 16 al observar un punto) pero aún así, debe ser de alguna manera posible generar un borde posicionado con precisión de profundidad completa – Pietro

+0

¿Cómo? el borde tiene solo cuatro posiciones diferentes, por lo que puede obtener solo 4 de 16 tonos. –

+0

por favor corrígeme si aún estoy equivocado Supongamos que la imagen ha sido escalada por 256 factor. Un borde tendría 256 posiciones, y un punto: 256^2 (que se redondearía) No sé, si eso es posible hacer en OpenGL (en este caso, el rendimiento no es un problema), pero yo En general, es posible generar imágenes que cumplan estos requisitos. Mi pregunta es justa: cómo hacerlo ... – Pietro

1

Aunque esté utilizando una proyección ortogonal, GL_PERSPECTIVE_CORRECTION_HINT podría tener un impacto en la precisión del procesamiento. Al menos recuerdo vagamente glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); arreglando algunos huecos en mi escena proyectada ortogonalmente hace muchos años.

+0

Gracias, agregó que, no cambió los resultados en este momento, pero tal vez será necesario en el futuro modo 3D – Pietro

Cuestiones relacionadas