2008-12-11 12 views
14

J'utilise PIL (Python Imaging Library). J'aimerais dessiner des polygones transparents. Il semble que la spécification d'une couleur de remplissage incluant le niveau alpha ne fonctionne pas. Sont leurs solutions de contournement?Comment dessiner des polygones transparents avec Python?

Si elle ne peut pas être fait en utilisant PIL Je suis prêt à utiliser autre chose.

S'il y a plus d'une solution, alors la performance devrait être pris en compte. Le dessin doit être aussi rapide que possible.

Répondre

2

J'utilise cairo + pycairo pour cela, et il fonctionne bien. Et vous pouvez partager des données d'image entre PIL et Cairo, en utilisant l'interface de tampon Python, s'il y a une opération dans Pil qui ne peut pas être faite dans le Caire.

2

Le module Image de PIL fournit une méthode de fusion.

Créez une deuxième image de la même taille que la première, avec un arrière-plan noir. Dessinez votre polygone dessus (avec la couleur pleine). Puis appelez Image.blend en passant les deux images et un niveau alpha. Il renvoie une troisième image, qui devrait avoir un polygone semi-transparent dessus.

Je n'ai pas mesuré la performance (hey, je n'ai pas encore essayé!) Donc je ne peux pas commenter sur sa pertinence. Je vous suggère de calculer votre budget de performance, puis de le mesurer pour voir s'il est assez rapide pour vos objectifs.

6

Ce que j'ai dû le faire lors de l'utilisation PIL pour dessiner des images transparentes est de créer une couche de couleur, une couche d'opacité avec le polygone dessiné sur elle, et les mélanger à la couche de base comme si:

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) 

Lorsque j'utilisais Image.Blend, j'avais des problèmes avec des comportements étranges de contour sur les polygones dessinés.

Le seul problème avec cette approche est que la performance est abyssale lors de l'élaboration d'un grand nombre de polygones de taille raisonnable. Une solution beaucoup plus rapide serait quelque chose comme "manuellement" dessiner le polygone sur une représentation de tableau de l'image.

-1

I a eu pour dessiner un polygone extérieur avec un contour, et soustraire des polygones internes (une opération courante dans SIG). Fonctionne comme un charme en utilisant la couleur (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

Cela n'a rien à voir avec la transparence. – Junuxx

1

D'après ce que j'ai trouvé, il ne peut pas être fait directement avec PIL. Voici une solution avec PyCairo. Le Caire est également utilisé par Mozilla, GTX +, Mono, Inkscape et WebKit, donc je pense que c'est un coffre-fort à utiliser en termes de support futur. Cela peut également être fait avec aggdraw, un add-on optionnel pour PIL. Voir ma source listée pour plus de détails. La version 2.7.3 de Python est utilisée.

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

fichier d'aide: 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 

Fichier 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

Ceci est pour oreiller, une fourchette plus maintenue de PIL. Si vous souhaitez dessiner des polygones transparents les uns par rapport aux autres, l'image de base doit être de type RVB, et non RGBA, et ImageDraw doit être de type RVBB.Exemple:

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

Ceci dessine deux triangles se chevauchant avec leur mélange de deux couleurs. C'est beaucoup plus rapide que de devoir composer plusieurs "couches" pour chaque polygone.

+0

Merci, c'est très utile. Je n'ai aucune idée de l'endroit où vous avez obtenu cette information - je ne la vois pas documentée. J'ai eu un comportement étrange en utilisant des combinaisons de RGB/RGBA autres que ceux que vous avez mentionnés ... – jwd

+0

Pourquoi écrivez-vous del drw mais pas del img? –

+0

Cela devrait être la réponse acceptée! – JeffThompson

Questions connexes