我想绘制一个多边形作为轮廓并用特定的颜色填充它。对于
PIL
来说,这应该是一个足够简单的任务...不幸的是,fill
参数产生的图像超出了轮廓...演示:
第 1 步,让我们清楚地展示我的轮廓应该是什么样子:
from PIL import Image, ImageDraw
vertices = [(44, 124),
(50, 48),
(74, 46),
(73, 123),
(44, 124)]
# draw as an outline
image = Image.new('RGB', (150, 150), 'black')
draw = ImageDraw.Draw(image)
draw.line(vertices, fill='blue', width=1)
image.save(r'outline.png')
这会产生下图:
这太棒了,我可以在 Photoshop 中确认我的角对应于指定的坐标。现在第 2 步,让我们使用
polygon
函数执行相同操作并绘制填充多边形:
# draw as a filled polygon
image = Image.new('RGB', (150, 150), 'black')
draw = ImageDraw.Draw(image)
draw.polygon(vertices, fill='white', outline='blue', width=1)
image.save(r'filled.png')
注意此形状上出现的两个像素(下面突出显示)
这是不可接受的。填充的多边形不应超出轮廓。这是我期望的输出(在 Photoshop 中模拟):
问题
在一天结束时,我想编写一个函数,它将采用
n
顶点来绘制一个带有填充边界且不超出轮廓的干净多边形。另外,由于技术原因,我无法使用 matplotlib
,这意味着我无法使用 skimage.draw.polygon_perimeter
,但任何其他软件包(特别是利用 numpy
)将是最好的
这是我当前的解决方案:使用
scipy.ndimage.binary_fill_holes
来填补这个洞。
import numpy as np
from scipy import ndimage
from PIL import Image, ImageDraw
vertices = [(44, 124),
(50, 48),
(74, 46),
(73, 123),
(44, 124)]
# draw the outline as a bitmap
outline = Image.new('1', (150, 150))
draw = ImageDraw.Draw(outline)
draw.line(vertices, fill=1, width=1)
outline = np.array(outline)
# fill with ndimage.binary_fill_holes
fill = ndimage.binary_fill_holes(outline)
# remove outline from fill using a logical "and"
fill = fill & ~outline
# create the final image
canvas = np.zeros((150,150,3), dtype=np.uint8)
canvas[fill == True] = [255, 255, 255] # fill with white
canvas[outline == True] = [0, 0, 255] # outline is blue
final = Image.fromarray(canvas)
final.save('final.png')
结果: