How do you draw transparent polygons with Python?

后端 未结 7 1276
独厮守ぢ
独厮守ぢ 2020-12-05 10:28

I\'m using PIL (Python Imaging Library). I\'d like to draw transparent polygons. It seems that specifying a fill color that includes alpha level does not work. Are their

相关标签:
7条回答
  • 2020-12-05 10:47

    I'm using cairo + pycairo for this, and it works well. And you can share image data between PIL and cairo, using python buffer interface, if there is operation in pil that can't be done in cairo.

    0 讨论(0)
  • 2020-12-05 10:57

    I had to draw an outside polygon with an outline, and subtract inner polygons (a common operation in GIS). Works like a charm using 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
    
    0 讨论(0)
  • 2020-12-05 10:58

    This is for Pillow, a more maintained fork of PIL. http://pillow.readthedocs.org/

    If you want to draw polygons that are transparent, relative to each other, the base Image has to be of type RGB, not RGBA, and the ImageDraw has to be of type RGBA. Example:

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

    This will draw two triangles overlapping with their two colors blending. This a lot faster than having to composite multiple 'layers' for each polygon.

    0 讨论(0)
  • 2020-12-05 10:58

    To do that you can use Shapely and OpenCV like this:

    import cv2
    import numpy as np
    from shapely.geometry import Polygon
    
    alpha = 0.5 # that's your transparency factor
    path = 'path_to_image.jpg'
    image = cv2.imread(path)
    (H, W) = image.shape[:2]
    
    xmin = 0
    ymin = 0 
    xmax = int(W / 2)
    ymax = int(H / 2)
    
    polygon = Polygon([(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)])
    int_coords = lambda x: np.array(x).round().astype(np.int32)
    exterior = [int_coords(polygon.exterior.coords)]
    
    overlay = image.copy()
    cv2.fillPoly(overlay, exterior, color=(255, 255, 0))
    cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0, image)
    cv2.imshow("Polygon", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    0 讨论(0)
  • 2020-12-05 10:59

    What I've had to do when using PIL to draw transparent images is create a color layer, an opacity layer with the polygon drawn on it, and composited them with the base layer as 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)
    

    When using Image.Blend I had issues with strange outlining behaviors on the drawn polygons.

    The only issue with this approach is that the performance is abysmal when drawing a large number of reasonably sized polygons. A much faster solution would be something like "manually" drawing the polygon on a numpy array representation of the image.

    0 讨论(0)
  • 2020-12-05 11:00

    PIL's Image module provides a blend method.

    Create a second image the same size as your first, with a black background. Draw your polygon on it (with full colour). Then call Image.blend passing the two images and an alpha level. It returns a third image, which should have a semi-transparent polygon on it.

    I haven't measured the performance (hey, I haven't even tried it!) so I cannot comment on it's suitability. I suggest you work out your performance budget, and then measure it to see if it is fast enough for your purposes.

    0 讨论(0)
提交回复
热议问题