Рисование границы неизвестной фигуры в Python

#python #python-imaging-library

Вопрос:

У меня есть изображение, которое состоит из прозрачного фона и (неизвестной) формы. Я хочу добавить черные пиксели по границе фигуры. Для этого я написал следующий сценарий. Он просто повторяет каждый пиксель и проверяет, является ли он частью фигуры. Если это так, он проверяет окружающие пиксели и устанавливает каждый прозрачный пиксель черным. Однако сценарий занимает ~1,5 секунды для примера изображения, что слишком медленно для моего случая использования. Как это можно сделать более эффективно/или есть ли лучший подход к этой проблеме?

 from PIL import Image, ImageDraw
from time import time

COLOR_TRANSPARENT = (0, 0, 0, 0)


def draw_random_shape(im):
    draw = ImageDraw.Draw(im, 'RGBA')
    draw.rectangle(((20, 200), (700, 300)), fill="red")
    draw.ellipse(((200, 300), (550, 750)), fill="blue")
    draw.line(((10, 75), (740, 680)), fill="yellow", width=50)


def add_border(im):
    color_border = (0, 0, 0, 255)
    pixels_set = set()
    size_x, size_y = im.size
    for x in range(size_x):
        for y in range(size_y):
            pixel = im.getpixel((x, y))
            if pixel[3] != 0 and pixel != color_border:
                for x_ in range(-1, 2):
                    for y_ in range(-1, 2):
                        pos_x = x   x_
                        pos_y = y   y_
                        if pos_x < 0 or pos_x >= size_x or pos_y < 0 or pos_y >= size_y:
                            continue
                        if (pos_x, pos_y) not in pixels_set:
                            pixel_ = im.getpixel((pos_x, pos_y))
                            if pixel_[3] == 0:
                                im.putpixel((pos_x, pos_y), color_border)
                            pixels_set.add((pos_x, pos_y))


if __name__ == '__main__':
    im = Image.new('RGBA', (800, 800), COLOR_TRANSPARENT)
    draw_random_shape(im)
    start_time = time()
    add_border(im)
    duration = time() - start_time
    print(f'Took {duration:.3f}s.')

    background_im = Image.new('RGBA', (800, 800), (255, 255, 255, 255))
    image = Image.alpha_composite(background_im, im)
    image.save("image.png", "png")