如何使用Python枕头库向PNG图像添加轮廓/描边/边框?

问题描述 投票:0回答:1

我正在尝试使用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)来做。

我试图用两种方法解决问题。

方法一

[第一种方法是创建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

如上图所示,此方法无效。它可能适用于简单的几何形状,但不适用于像这样的复杂形状。

方法二

第二种方法是将脑图像像素数据加载到二维数组中,然后遍历所有像素。检查每个像素的颜色,并检查每个不透明的像素的颜色(在rgbA形式中,A(或Alpha)不为0),在像素的上,下,右,左,主对角线下方绘制一个黑色像素,主对角线向上,辅助对角线(/)向下,辅助对角线(/)向上。然后在上方的第二个像素,下方的第二个像素等等中绘制一个像素,这是通过“ for循环”完成的,其中重复次数是所需的笔划宽度(在此示例中为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库更轻松,更好的方法来达到想要的结果。我该怎么做?而且,如何固定循环代码(我了解有关Numpy和OpenCV的一些知识,对于此目的而言更好?)

[我知道,如果电话应用程序可以在几毫秒内完成,python也可以,但是我找不到任何方法。

谢谢。

python python-imaging-library border image-manipulation
1个回答
0
投票

由于我还有其他承诺,目前我无法为您提供经过全面测试的Python解决方案,但是我可以肯定地向您展示如何在几毫秒内完成该操作,并为您提供一些指导。

我刚刚在命令行上使用了ImageMagick。它可以在Linux和macOS(使用brew install imagemagick)和Windows上运行。因此,我提取了alpha / transparency通道并丢弃了所有颜色信息。然后,使用形态学“ edge out”操作在alpha通道中的形状边缘周围生成粗线。然后,我反转白色边缘,使它们变为黑色,并使所有白色像素透明。然后叠加在原始图像的顶部。

这是完整的命令:

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

这样就基本上打开了图像,将括号内的alpha层的克隆副本弄乱了,然后将产生的黑色轮廓变平回到原始图像并保存。让我们一次执行一个步骤:

将alpha层提取为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

这是最终结果,对于较粗的行,将octagon:9更改为octagon:19

enter image description here


因此,使用PIL ...,您需要打开图像并转换为RGBA,然后分割通道。您无需触摸RGB,只需触摸A通道即可。

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

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

这里需要一些形态-参见here

将原始RGB通道与新的A通道合并并保存:

result = Image.merge((R,G,B,modifiedA))
result.save('result.png')
© www.soinside.com 2019 - 2024. All rights reserved.