2008-12-11 27 views
14

Estoy usando PIL (biblioteca de imágenes de Python). Me gustaría dibujar polígonos transparentes. Parece que especificar un color de relleno que incluya un nivel alfa no funciona. Son sus soluciones?¿Cómo se dibujan polígonos transparentes con Python?

Si no se puede hacer usando PIL, estoy dispuesto a usar otra cosa.

Si hay más de una solución, se debe tener en cuenta el rendimiento. El dibujo debe ser lo más rápido posible.

Respuesta

2

Estoy usando cairo + pycairo para esto, y funciona bien. Y puede compartir datos de imagen entre PIL y cairo, usando la interfaz de búfer de python, si hay una operación en pil que no se puede hacer en cairo.

2

El módulo de imagen de PIL proporciona un método de combinación.

Cree una segunda imagen del mismo tamaño que la primera, con un fondo negro. Dibuja tu polígono en él (con color completo). Luego llama a Image.blend pasando las dos imágenes y un nivel alfa. Devuelve una tercera imagen, que debería tener un polígono semitransparente.

No he medido el rendimiento (hey, ¡ni siquiera lo he probado!) Así que no puedo comentar sobre su idoneidad. Le sugiero que elabore su presupuesto de rendimiento y luego mida para ver si es lo suficientemente rápido para sus propósitos.

6

lo que he tenido que hacer cuando se utiliza PIL para dibujar imágenes transparentes es crear una capa de color, una capa de opacidad con el polígono dibujado en él, y ellos, mezclados con la capa de base como así:

color_layer = Image.new('RGBA', base_layer.size, fill_rgb) 
alpha_mask = Image.new('L', base_layer.size, 0) 
alpha_mask_draw = ImageDraw.Draw(alpha_mask) 
alpha_mask_draw.polygon(self.outline, fill=fill_alpha) 
base_layer = Image.composite(color_layer, base_layer, alpha_mask) 

Al usar Image.Blend, tuve problemas con comportamientos extraños en los polígonos dibujados.

El único problema con este enfoque es que el rendimiento es abismal al dibujar un gran número de polígonos de tamaño razonable. Una solución mucho más rápida sería algo así como dibujar "manualmente" el polígono en una representación de matriz numpy de la imagen.

-1

Tuve que dibujar un polígono exterior con un contorno y restar polígonos internos (una operación común en GIS). Funciona como un amuleto usando el color (255,255,255,0).

image = Image.new("RGBA", (100,100)) 
drawing = ImageDraw.Draw(i) 
for index, p in enumerate(polygons): 
    if index == 0: 
     options = { 'fill': "#AA5544", 
        'outline': "#993300"} 
    else: 
     options = {'fill': (255,255,255,0)} 
    drawing.polygon(p, **options) 

buf= StringIO.StringIO() 
i.save(buf, format= 'PNG') 
# do something with buf 
+1

Esto no tiene nada que ver con la transparencia. – Junuxx

1

Por lo que he encontrado, no se puede hacer directamente con PIL. Aquí hay una solución con PyCairo. Cairo también es utilizado por Mozilla, GTX +, Mono, Inkscape y WebKit, así que creo que es seguro usarlo en términos de soporte futuro. También se puede hacer con aggdraw, un complemento opcional para PIL. Vea mi fuente en la lista para más detalles. Python versión 2.7.3 es usada.

Fuente: http://livingcode.org/2008/12/14/drawing-with-opacity.1.html

archivo Asistente: random_polys_util.py

MIN_ALPHA = 50 
    MAX_ALPHA = 100 

    WIDTH = 500 
    HEIGHT = 250 

    # 
    # Utilities 
    # 
    def hex2tuple(hex_color): 
     return tuple([int(hex_color[i:i+2], 16) for i in range(1,9,2)]) 

    def tuple2hex(tuple_color): 
     return "#%0.2X%0.2X%0.2X%0.2X" % tuple_color 

    def ints2floats(tuple_color): 
     return tuple([c/255.0 for c in tuple_color]) 

    def inc_point(p, dp): 
     return (p[0] + dp[0]) % WIDTH, (p[1] + dp[1]) % HEIGHT 

    def inc_triangle(t, dt): 
     return tuple([inc_point(t[i], dt[i]) for i in range(3)]) 

    def inc_color(c, dc): 
     new_c = [(c[i] + dc[i]) % 256 for i in range(3)] 
     new_a = (c[3] + dc[3]) % MAX_ALPHA 
     if new_a < MIN_ALPHA: new_a += MIN_ALPHA 
     new_c.append(new_a) 
     return tuple(new_c) 

    def draw_all(draw_fn): 
     triangle = start_t 
     color = start_c 
     for i in range(50): 
      triangle = inc_triangle(triangle, dt) 
      color = inc_color(color, dc) 
      draw_fn(triangle, color) 

    # 
    # Starting and incrementing values 
    # 
    start_c = hex2tuple('E6A20644') 
    start_t = (127, 132), (341, 171), (434, 125) 
    dt = (107, 23), (47, 73), (13, 97) 
    dc = 61, 113, 109, 41 

archivo principal: random_polys.py

from random_polys_util import * 

def cairo_poly(pts, clr): 
    ctx.set_source_rgba(*ints2floats(clr)) 
    ctx.move_to(*pts[-1]) 
    for pt in pts: 
     ctx.line_to(*pt) 
    ctx.close_path() 
    ctx.fill() 

def cairo_main(): 
    # Setup Cairo 
    import cairo 
    global ctx 
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) 
    ctx = cairo.Context(surface) 
    # fill background white 
    cairo_poly(((0,0),(WIDTH,0),(WIDTH,HEIGHT),(0,HEIGHT)),(255,255,255,255)) 
    draw_all(cairo_poly) 
    surface.write_to_png('cairo_example.png') 

def main(): 
    cairo_main() 

if __name__ == "__main__": 
    main() 
28

Esto es para almohada, un tenedor más sostenido de PIL. http://pillow.readthedocs.org/

Si desea dibujar polígonos que sean transparentes, relativos entre sí, la imagen base debe ser de tipo RGB, no RGBA, y el ImageDraw debe ser de tipo RGBA.Ejemplo:

from PIL import Image, ImageDraw 

img = Image.new('RGB', (100, 100)) 
drw = ImageDraw.Draw(img, 'RGBA') 
drw.polygon([(50, 0), (100, 100), (0, 100)], (255, 0, 0, 125)) 
drw.polygon([(50,100), (100, 0), (0, 0)], (0, 255, 0, 125)) 
del drw 

img.save('out.png', 'PNG') 

Esto dibujará dos triángulos superpuestos con sus dos colores mezclados. Esto es mucho más rápido que tener que componer múltiples 'capas' para cada polígono.

+0

Gracias, esto es muy útil. No tengo idea de dónde obtuvo esa información, no la veo documentada. Obtuve un comportamiento extraño al usar combinaciones de RGB/RGBA distintas a las que mencionas ... – jwd

+0

¿Por qué escribes del drw pero no del img? –

+0

¡Esta debería ser la respuesta aceptada! – JeffThompson

Cuestiones relacionadas