Нарисуйте эллипс в Python PIL с толщиной линии

Я пытаюсь нарисовать круг на изображении, используя Python. Я пробовал это с помощью PIL, но я хотел бы указать linewidth. В настоящее время PIL рисует круг, но граница слишком тонкая.

вот что я сделал.

для тестового изображения: я создал изображение 1632 X 1200 в MS Paint и заполнил его зеленым цветом. Я назвал его 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

: как вы можете видеть, нижний левый и верхний правый слишком тонкие. Кроме того, существуют зазоры между различными кругами (см. верхний левый и нижний правый).

круг имеет различную толщину. Я ищете круг с равномерной толщиной.

вопрос: Есть ли способ нарисовать круг в Python, на изображении, таком как test_1.формат JPG, используя PIL, NumPy, etc. и для указания толщины линии?

3 ответов


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

выход С и без сглаживания

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 без серьезных изменений.


простое (но не приятное) решение-нарисовать два круга (меньший с цветом фона):

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)

Я не думаю, что есть способ указать толщину эллипса, но вы, вероятно, можете рисовать линии в каждом пикселе, где проходит эллипс, с аргументом width=...

NB: я иностранец, так что извините, если мой английский не так.