web-dev-qa-db-ja.com

楕円をPython PILと線の太さで描画します

Pythonを使用して画像に円を描画しようとしています。 PILを使用してこれを試しましたが、linewidthを指定したいと思います。現在、PILは円を描きますが、境界線が細すぎます。

これが私がしたことです。

テスト画像の場合:MSペイントで1632 X 1200の画像を作成し、緑色で塗りつぶしました。私はそれをtest_1.jpgと呼びました。入力ファイルは次のとおりです。 Input

from PIL import Image, ImageDraw

im = Image.open('test_1.jpg')

width, height = im.size
eX, eY = 816,816 #Size of Bounding Box for ellipse

bbox =  (width/2 - eX/2, height/2 - eY/2, width/2 + eX/2, height/2 + eY/2)

draw = ImageDraw.Draw(im)
bbox_L = []
for j in range(0,5):
    bbox_L.append([element+j for element in bbox])
    draw.ellipse(Tuple(bbox_L[j]), outline ='white')

im.show()

基本的には、同じ場所を中心に半径が異なる複数の円を描いてみました。太い線の効果が出ると思いました。

ただし、これにより、以下の添付ファイルに示す出力が生成されます。 Output

問題:ご覧のとおり、左下と右上が薄すぎます。また、さまざまな円の間にギャップがあります(左上と右下を参照)。

円の太さはさまざまです。均一な太さの円を探しています。

質問: PIL、NumPyなどを使用してtest_1.jpgのような画像に、Pythonで円を描く方法はありますか線の太さを指定するには

14
edesz

私も同じ問題を抱えていたので、あなたと同じようなヘルパー関数を書くことにしました。この関数は、マスクレイヤー上に白黒で2つの同心楕円を描画し、目的のアウトラインカラーがマスクを介して元の画像にスタンプされます。よりスムーズな結果(アンチエイリアス)を取得するために、楕円とマスクはより高い解像度で描画されます。

アンチエイリアスがある場合とない場合の出力

ellipses with PIL

白い楕円の幅は20ピクセル、黒い楕円の幅は0.5ピクセルです。

コード

from PIL import Image, ImageDraw

def draw_ellipse(image, bounds, width=1, outline='white', antialias=4):
    """Improved ellipse drawing function, based on PIL.ImageDraw."""

    # Use a single channel image (mode='L') as mask.
    # The size of the mask can be increased relative to the imput image
    # to get smoother looking results. 
    mask = Image.new(
        size=[int(dim * antialias) for dim in image.size],
        mode='L', color='black')
    draw = ImageDraw.Draw(mask)

    # draw outer shape in white (color) and inner shape in black (transparent)
    for offset, fill in (width/-2.0, 'white'), (width/2.0, 'black'):
        left, top = [(value + offset) * antialias for value in bounds[:2]]
        right, bottom = [(value - offset) * antialias for value in bounds[2:]]
        draw.ellipse([left, top, right, bottom], fill=fill)

    # downsample the mask using PIL.Image.LANCZOS 
    # (a high-quality downsampling filter).
    mask = mask.resize(image.size, Image.LANCZOS)
    # paste outline color to input image through the mask
    image.paste(outline, mask=mask)

# green background image
image = Image.new(mode='RGB', size=(700, 300), color='green')

ellipse_box = [50, 50, 300, 250]

# draw a thick white ellipse and a thin black ellipse
draw_ellipse(image, ellipse_box, width=20)

# draw a thin black line, using higher antialias to preserve finer detail
draw_ellipse(image, ellipse_box, outline='black', width=.5, antialias=8)

# Lets try without antialiasing
ellipse_box[0] += 350 
ellipse_box[2] += 350 

draw_ellipse(image, ellipse_box, width=20, antialias=1)
draw_ellipse(image, ellipse_box, outline='black', width=1, antialias=1)

image.show()

私はこのコードをpython 3.4でテストしただけですが、大きな変更を加えなくても2.7で動作するはずです。

12
Håken Lid

単純な(しかしニースではない)解決策は、2つの円(背景色の小さい方の円)を描くことです。

outline = 10 # line thickness
draw.ellipse((x1-outline, y1-outline, x2+outline, y2+outline), fill=outline_color)
draw.ellipse((x1, y1, x2, y2), fill=background_color)
5
matousc

楕円の厚さを指定する方法はないと思いますが、引数width = ..を使用して、楕円が通過する各ピクセルに線を引くことができます。

注意:私は外国人なので、英語が間違っていたらごめんなさい。

0
Mika

このようなImage.core.drawメソッドを使用できます

   `zero_array = np.zeros((224,224))
    im = Image.fromarray(np.uint8(zero_array))
    draw = ImageDraw.Draw(im)
    dr_im = Image.core.draw(im.getdata(), 0)
    dr_im.draw_rectangle((22,33, 150,100),220,2)
    dr_im.draw_rectangle((22,33, 150,100),125,0)
    #draw.rectangle((22,33, 150,100), fill=220,outline = 125)
    print(np.array(im)[33][23])
    im.show()`
0
wang wang