私は PIL (Python Imaging Library) を使用しています。透明なポリゴンを描きたいです。アルファ レベルを含む塗りつぶしの指定が機能しないようです。彼らの回避策はありますか?
PIL を使用して実行できない場合は、別のものを使用します。
複数のソリューションがある場合は、パフォーマンスを考慮に入れる必要があります。描画はできるだけ高速にする必要があります。
私は PIL (Python Imaging Library) を使用しています。透明なポリゴンを描きたいです。アルファ レベルを含む塗りつぶしの指定が機能しないようです。彼らの回避策はありますか?
PIL を使用して実行できない場合は、別のものを使用します。
複数のソリューションがある場合は、パフォーマンスを考慮に入れる必要があります。描画はできるだけ高速にする必要があります。
これは、PIL のより保守的なフォークである Pillow 用です。http://pillow.readthedocs.org/
相互に相対的に透明なポリゴンを描画する場合、ベース イメージは RGBA ではなく RGB タイプである必要があり、ImageDraw は RGBA タイプである必要があります。例:
from PIL import Image, ImageDraw
img = Image.new('RGB', (100, 100))
drw = ImageDraw.Draw(img, 'RGBA')
drw.polygon(xy=[(50, 0), (100, 100), (0, 100)], fill=(255, 0, 0, 125))
drw.polygon(xy=[(50, 100), (100, 0), (0, 0)], fill=(0, 255, 0, 125))
del drw
img.save('out.png', 'PNG')
これにより、2 つの色が混ざり合って重なり合う 2 つの三角形が描画されます。これは、ポリゴンごとに複数の「レイヤー」を合成するよりもはるかに高速です。
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 を使用すると、描画されたポリゴンで奇妙なアウトライン動作の問題が発生しました。
このアプローチの唯一の問題は、適切なサイズのポリゴンを大量に描画するときにパフォーマンスが低下することです。はるかに高速なソリューションは、画像のnumpy配列表現にポリゴンを「手動で」描画するようなものです。
PILの画像モジュールはブレンド方法を提供します。
背景が黒で、最初の画像と同じサイズの2番目の画像を作成します。その上にポリゴンを描画します(フルカラーで)。次に、Image.blendを呼び出して、2つの画像とアルファレベルを渡します。3番目の画像を返します。この画像には、半透明のポリゴンが含まれている必要があります。
私はパフォーマンスを測定していません(ねえ、私も試していません!)ので、その適合性についてコメントすることはできません。パフォーマンスバジェットを計算し、それを測定して、目的に十分な速さがあるかどうかを確認することをお勧めします。
これにはcairo + pycairoを使用していますが、うまく機能します。また、cairo では実行できない操作が pil にある場合は、python バッファー インターフェイスを使用して、PIL と cairo 間で画像データを共有できます。
私が発見したことから、PILで直接行うことはできません。PyCairo を使用したソリューションを次に示します。Cairo は Mozilla、GTX+、Mono、Inkscape、WebKit でも使用されているので、今後のサポート面でも安心して使えると思います。また、PIL のオプションのアドオンである aggdraw を使用して実行することもできます。詳細については、リストされているソースを参照してください。Python バージョン 2.7.3 が使用されます。
ソース: http://livingcode.org/2008/12/14/drawing-with-opacity.1.html
ヘルパー ファイル: 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()
アウトラインを使用して外側のポリゴンを描画し、内側のポリゴンを減算する必要がありました (GIS での一般的な操作)。色を使った魅力のように機能します(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