2008-12-11 9 views
14

Ich benutze PIL (Python Imaging Library). Ich möchte transparente Polygone zeichnen. Es scheint, dass das Angeben einer Füllfarbe, die Alpha-Ebene enthält, nicht funktioniert. Sind ihre Workarounds?Wie zeichnen Sie transparente Polygone mit Python?

Wenn es nicht mit PIL getan werden kann, bin ich bereit, etwas anderes zu verwenden.

Wenn es mehr als eine Lösung gibt, sollte die Leistung berücksichtigt werden. Die Zeichnung muss so schnell wie möglich sein.

Antwort

2

Ich benutze cairo + pycairo für diese, und es funktioniert gut. Und Sie können Bilddaten zwischen PIL und Cairo mit der Python-Buffer-Schnittstelle freigeben, wenn es in pil eine Operation gibt, die in Kairo nicht möglich ist.

2

Das Image-Modul von PIL bietet eine Mischmethode.

Erstellen Sie ein zweites Bild mit der gleichen Größe wie Ihr erstes, mit einem schwarzen Hintergrund. Zeichnen Sie Ihr Polygon darauf (mit voller Farbe). Rufen Sie dann Image.blend auf, indem Sie die zwei Bilder und eine Alpha-Ebene übergeben. Es gibt ein drittes Bild zurück, das ein halbtransparentes Polygon haben sollte.

Ich habe die Leistung nicht gemessen (hey, ich habe es noch nicht einmal probiert!), Also kann ich nichts dazu sagen. Ich schlage vor, dass Sie Ihr Leistungsbudget berechnen und dann messen, um zu sehen, ob es für Ihre Zwecke schnell genug ist.

6

Was ich tun musste, wenn PIL mit transparenten Bilder zu zeichnen ist eine Farbschicht zu schaffen, eine Opazität Schicht mit dem Polygon auf sie gezogen, und Compositing sie mit der Basisschicht als so:

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) 

Bei der Verwendung von Image.Blend hatte ich Probleme mit seltsamen Umrissverhalten auf den gezeichneten Polygonen.

Das einzige Problem bei diesem Ansatz ist, dass die Leistung beim Zeichnen einer großen Anzahl von Polygonen vernünftiger Größe miserabel ist. Eine viel schnellere Lösung wäre etwas wie "manuelles" Zeichnen des Polygons auf eine numplige Array-Darstellung des Bildes.

-1

Ich musste ein äußeres Polygon mit einem Umriss zeichnen und innere Polygone subtrahieren (eine übliche Operation in GIS). Funktioniert wie ein Charm mit der Farbe (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

Das hat nichts mit Transparenz zu tun. – Junuxx

1

Von dem, was ich gefunden habe, kann es nicht direkt mit PIL getan werden. Hier ist eine Lösung mit PyCairo. Cairo wird auch von Mozilla, GTX +, Mono, Inkscape und WebKit verwendet, daher denke ich, dass es in Bezug auf zukünftige Unterstützung sicher ist. Es kann auch mit Aggdraw, einem optionalen Add-on für PIL, durchgeführt werden. Weitere Informationen finden Sie in meiner Quellenangabe. Python Version 2.7.3 wird verwendet.

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

Helper-Datei: 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 

Hauptdatei: 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

Dies ist für Kissen, eine beibehalten Gabel von PIL. http://pillow.readthedocs.org/

Wenn Sie Polygone zeichnen möchten, die relativ zueinander transparent sind, muss das Basis-Image vom Typ RGB sein, nicht RGBA, und das ImageDraw muss vom Typ RGBA sein.Beispiel:

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

Dies wird zwei Dreiecke zeichnen, die sich mit ihrer Mischung aus zwei Farben überlappen. Dies ist viel schneller, als mehrere Ebenen für jedes Polygon zusammenzusetzen.

+0

Danke, das ist sehr nützlich. Ich habe keine Ahnung, woher du diese Information hast - ich sehe sie nicht dokumentiert. Ich habe ein seltsames Verhalten bei der Verwendung von Kombinationen von RGB/RGBA anders als die, die Sie erwähnt haben ... – jwd

+0

Warum schreiben Sie del drw aber nicht del img? –

+0

Dies sollte die akzeptierte Antwort sein! – JeffThompson