2008-12-11 3 views
14

Я использую PIL (Python Imaging Library). Я бы хотел нарисовать прозрачные полигоны. Кажется, что указание цвета заливки, которое включает альфа-уровень, не работает. Их обходные пути?Как рисовать прозрачные полигоны с Python?

Если это невозможно, используя PIL, я готов использовать что-то еще.

Если есть несколько решений, тогда необходимо учитывать производительность. Рисунок должен быть как можно быстрее.

ответ

2

Я использую cairo + pycairo для этого, и он работает хорошо. И вы можете обмениваться данными изображения между PIL и cairo, используя интерфейс буфера python, если в пиле есть операция, которая не может быть выполнена в cairo.

2

Модуль изображения PIL предоставляет метод наложения.

Создайте второе изображение того же размера, что и ваш первый, с черным фоном. Нарисуйте на нем свой многоугольник (с полным цветом). Затем вызовите Image.blend, передавая два изображения и альфа-уровень. Он возвращает третье изображение, на котором должен быть полупрозрачный многоугольник.

Я не оценил производительность (эй, я даже не пробовал!), Поэтому я не могу прокомментировать его пригодность. Я предлагаю вам разработать свой бюджет производительности, а затем измерить его, чтобы узнать, достаточно ли он для ваших целей.

6

То, что я должен был сделать, используя PIL рисовать прозрачные изображения, создает цветовой слой, непрозрачность слой с полигоном, нарисованным на нем, и скомпонован их с базовым слоем, как так:

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) 

При использовании Image.Blend у меня были проблемы со странным описанием поведения на рисованных полигонах.

Единственная проблема с этим подходом заключается в том, что производительность является ужасной при рисовании большого количества полигонов разумного размера. Гораздо более быстрое решение было бы чем-то вроде «вручную» рисования многоугольника на представлении изображения в виде нескольких цифр.

-1

Мне пришлось нарисовать внешний многоугольник с контуром и вычесть внутренние многоугольники (общая операция в ГИС). Работает как шарм, используя цвет (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

Это не имеет ничего общего с прозрачностью. – Junuxx 2012-05-20 23:10:22

1

Из-за того, что я нашел, это не может быть сделано непосредственно с PIL. Вот решение с PyCairo. Cairo также используется Mozilla, GTX +, Mono, Inkscape и WebKit, поэтому я думаю, что это безопасно использовать с точки зрения будущей поддержки. Это также можно сделать с помощью aggdraw, дополнительного дополнения для PIL. Дополнительную информацию см. В моем источнике. Используется версия 2.7.3 Python.

Источник: http://livingcode.org/2008/12/14/drawing-with-opacity.1.html

Helper файл: 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 

Главный файл: 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

Это для подушки, более поддерживаемой развилки PIL. http://pillow.readthedocs.org/

Если вы хотите нарисовать полигоны, которые являются прозрачными, относительно друг друга, базовое изображение должно быть типа RGB, а не RGBA, а ImageDraw должно иметь тип RGBA.Пример:

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

Это нарисовано двумя треугольниками, перекрывающимися их смесями двух цветов. Это намного быстрее, чем наличие сложных многослойных слоев для каждого многоугольника.

+0

Спасибо, это очень полезно. Я понятия не имею, где вы получили эту информацию - я не вижу ее документированной. У меня появилось странное поведение при использовании комбинаций RGB/RGBA, отличных от тех, которые вы упомянули ... – jwd 2015-09-24 01:45:59

Смежные вопросы