Как добавить контур / обводку / границу к изображению PNG с библиотекой подушек в Python? - PullRequest
1 голос
/ 24 апреля 2020

Я пытаюсь использовать библиотеку Pillow (python -imaging-library) Python, чтобы создать контур / обводку / границу (с любым выбранным цветом и шириной) вокруг моего изображения .png. Здесь вы можете увидеть исходное изображение и мой требуемый результат (созданный приложением для телефона): https://i.stack.imgur.com/4x4qh.png

Вы можете скачать png-файл исходного изображения здесь: https://pixabay.com/illustrations/brain-character-organ-smart-eyes-1773885/

Я сделал это в среднем размере (1280x1138), но, возможно, лучше сделать это с наименьшим размером (640x569).

Я попытался решить проблему двумя способами.

METHOD ONE

Первый способ - создать полностью черное изображение изображения brain.png, увеличить его и вставить оригинальный цветной мозг изображение поверх него. Вот мой код:

brain_black = Image.open("brain.png") #load brain image
width = brain_black.width #in order not to type a lot
height = brain_black.height #in order not to type a lot
rectangle = Image.new("RGBA", (width, height), "black") #creating a black rectangle in the size of the brain image
brain_black.paste(rectangle, mask=brain_black) #pasting on the brain image the black rectangle, and masking it with the brain picture

#now brain_black is the brain.png image, but all its pixels are black. Let's continue:

brain_black = brain_black.resize((width+180, height+180)) #resizing the brain_black by some factor
brain_regular = Image.open("brain.png") #load the brain image in order to paste later on
brain_black.paste(brain_regular,(90,90), mask=brain_regular) #paste the regular (colored) brain on top of the enlarged black brain (in x=90, y=90, the middle of the black brain)
brain_black.save("brain_method_resize.png") #saving the image

Этот метод не работает, как вы можете видеть на ссылке выше. Он мог бы работать для простых форм геометрии c, но не для такой сложной формы, как эта.

МЕТОД ДВА

Второй метод заключается в загрузке данных пикселей изображения мозга в двумерный массив и l oop по всем пикселям. Проверьте цвет каждого пикселя, и в каждом непрозрачном пикселе (означает, что A (или Альфа) не равен 0 в форме rgbA), чтобы нарисовать черный пиксель в пикселе выше, ниже, справа, влево, главной диагонали вниз, главная диагональ вверх, вторичная диагональ (/) вниз и вторичная диагональ (/) вверх. Затем нарисовать пиксель во втором пикселе выше, второй пиксель внизу и т. Д. c. это было сделано с помощью «для l oop», где число повторений - это желаемая ширина хода (в этом примере - 30). Вот мой код:

brain=Image.open("brain.png") #load brain image
background=Image.new("RGBA", (brain.size[0]+400, brain.size[1]+400), (0, 0, 0, 0)) #crate a background transparent image to create the stroke in it
background.paste(brain, (200,200), brain) #paste the brain image in the middle of the background
pixelsBrain = brain.load() #load the pixels array of brain
pixelsBack=background.load() #load the pixels array of background

for i in range(brain.size[0]):
    for j in range(brain.size[1]):
        r, c = i+200, j+200 #height and width offset 
        if(pixelsBrain[i,j][3]!=0): #checking if the opacity is not 0, if the alpha is not 0.
            for k in range(30): #the loop
                pixelsBack[r, c + k] = (0, 0, 0, 255)
                pixelsBack[r, c - k] = (0, 0, 0, 255)
                pixelsBack[r + k, c] = (0, 0, 0, 255)
                pixelsBack[r - k, c] = (0, 0, 0, 255)
                pixelsBack[r + k, c + k] = (0, 0, 0, 255)
                pixelsBack[r - k, c - k] = (0, 0, 0, 255)
                pixelsBack[r + k, c - k] =(0, 0, 0, 255)
                pixelsBack[r - k, c + k] = (0, 0, 0, 255)

background.paste(brain, (200,200), brain) #pasting the colored brain onto the background, because the loop "destroyed" the picture.

background.save("brain_method_loop.png")

Этот метод работал, но он очень отнимает много времени (занимает около 30 секунд только для одного изображения и обводки 30 пикселей). Я хочу сделать это для многих фотографий, поэтому этот метод мне не подходит.

Существует ли более простой и лучший способ достичь желаемого результата с помощью библиотеки Python Pillow. Как мне это сделать? А также, как я могу закрепить свой код l oop (я кое-что понял о Numpy и OpenCV, что лучше для этой цели?)

Я знаю, что если приложение для телефона может сделать это в за считанные миллисекунды тоже может python, но я не нашел способа сделать это.

Спасибо.

1 Ответ

1 голос
/ 26 апреля 2020

Я не могу сделать для вас полностью протестированное Python решение на данный момент, так как у меня есть другие обязательства, но я, конечно, могу показать вам, как это сделать, за несколько миллисекунд и дать вам несколько советов.

Я только что использовал ImageMagick в командной строке. Он работает на Linux и macOS (используйте brew install imagemagick) и Windows. Итак, я извлекаю канал альфа / прозрачности и отбрасываю всю информацию о цвете. Затем используйте морфологическую операцию "edge out" , чтобы создать жирную линию по краям фигуры в альфа-канале. Затем я инвертирую белые края, чтобы они стали черными и сделали все белые пиксели прозрачными. Затем наложите поверх исходного изображения.

Вот полная команда:

magick baby.png \( +clone -alpha extract -morphology edgeout octagon:9  -threshold 10% -negate -transparent white \) -flatten result.png

Таким образом, это в основном открывает изображение, портится с клонированной копией альфа-слоя внутри скобок и затем сглаживает черный контур, который возвращается на исходное изображение, и сохраняет его. Давайте сделаем шаги по одному:

Извлеките альфа-слой как alpha.png:

magick baby.png -alpha extract alpha.png

enter image description here

Теперь откормитесь края, инвертировать и сделать все, что не черным, становятся прозрачными и сохраняются как overlay.png:

magick alpha.png -morphology edgeout octagon:9  -threshold 10% -negate -transparent white overlay.png

enter image description here

Вот окончательный результат, измените * От 1033 * до octagon:19 для жирных линий:

enter image description here


Итак, с PIL ... вам нужно открыть изображение и преобразовать в RGBA, затем разделите каналы. Вам не нужно прикасаться к каналам RGB только к каналу A.

im = Image.open('baby.png').convert('RGBA')

R, G, B, A = im.split()

Здесь требуется некоторая морфология - см. здесь .

Объедините оригинальные каналы RGB с новый канал A и сохраните:

result = Image.merge((R,G,B,modifiedA))
result.save('result.png')

Обратите внимание, что существует Python привязок к ImageMagick с именем wand, и вам может быть проще перевести мои вещи из командной строки с помощью этого ... палочка . Кроме того, scikit-image имеет простой в использовании набор морфологии тоже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...