Python SciPy 创建 2D 多边形蒙版

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3654289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:06:18  来源:igfitidea点击:

SciPy Create 2D Polygon Mask

pythonscipypolygonsagepoint-in-polygon

提问by Isaac Sutherland

I need to create a numpy 2D array which represents a binary mask of a polygon, using standard Python packages.

我需要使用标准 Python 包创建一个 numpy 2D 数组,它表示多边形的二进制掩码。

  • input: polygon vertices, image dimensions
  • output: binary mask of polygon (numpy 2D array)
  • 输入:多边形顶点,图像尺寸
  • 输出:多边形的二进制掩码(numpy 2D 数组)

(Larger context: I want to get the distance transform of this polygon using scipy.ndimage.morphology.distance_transform_edt.)

(更大的背景:我想使用 scipy.ndimage.morphology.distance_transform_edt 获得这个多边形的距离变换。)

Can anyone show me how to do this?

谁能告诉我如何做到这一点?

采纳答案by Isaac Sutherland

The answer turns out to be quite simple:

答案很简单:

import numpy
from PIL import Image, ImageDraw

# polygon = [(x1,y1),(x2,y2),...] or [x1,y1,x2,y2,...]
# width = ?
# height = ?

img = Image.new('L', (width, height), 0)
ImageDraw.Draw(img).polygon(polygon, outline=1, fill=1)
mask = numpy.array(img)

回答by Anil

You could try to use python's Image Library, PIL. First you initialize the canvas. Then you create a drawing object, and you start making lines. This is assuming that the polygon resides in R^2 and that the vertex list for the input are in the correct order.

您可以尝试使用 python 的图像库 PIL。首先初始化画布。然后创建一个绘图对象,然后开始制作线条。这是假设多边形位于 R^2 中并且输入的顶点列表的顺序正确。

Input = [(x1, y1), (x2, y2), ..., (xn, yn)] , (width, height)

输入 = [(x1, y1), (x2, y2), ..., (xn, yn)] , (width, height)

from PIL import Image, ImageDraw

img = Image.new('L', (width, height), 0)   # The Zero is to Specify Background Color
draw = ImageDraw.Draw(img)

for vertex in range(len(vertexlist)):
    startpoint = vertexlist[vertex]
    try: endpoint = vertexlist[vertex+1]
    except IndexError: endpoint = vertexlist[0] 
    # The exception means We have reached the end and need to complete the polygon
    draw.line((startpoint[0], startpoint[1], endpoint[0], endpoint[1]), fill=1)

# If you want the result as a single list
# You can make a two dimensional list or dictionary by iterating over the height and width variable
list(img.getdata())

# If you want the result as an actual Image
img.save('polgon.jpg', 'JPEG')

Is this what you were looking for, or were you asking something different?

这是您要找的东西,还是您要问一些不同的东西?

回答by Joe Kington

As a slightly more direct alternative to @Anil's answer, matplotlib has matplotlib.nxutils.points_inside_polythat can be used to quickly rasterize an arbitrary polygon. E.g.

作为@Anil 答案的更直接的替代方法,matplotlibmatplotlib.nxutils.points_inside_poly可用于快速栅格化任意多边形。例如

import numpy as np
from matplotlib.nxutils import points_inside_poly

nx, ny = 10, 10
poly_verts = [(1,1), (5,1), (5,9),(3,2),(1,1)]

# Create vertex coordinates for each grid cell...
# (<0,0> is at the top left of the grid in this system)
x, y = np.meshgrid(np.arange(nx), np.arange(ny))
x, y = x.flatten(), y.flatten()

points = np.vstack((x,y)).T

grid = points_inside_poly(points, poly_verts)
grid = grid.reshape((ny,nx))

print grid

Which yields (a boolean numpy array):

产生(一个布尔 numpy 数组):

[[False False False False False False False False False False]
 [False  True  True  True  True False False False False False]
 [False False False  True  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False  True False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]]

You should be able to pass gridto any of the scipy.ndimage.morphology functions quite nicely.

您应该能够grid很好地传递给任何 scipy.ndimage.morphology 函数。

回答by Yusuke N.

An update on Joe's comment. Matplotlib API has changed since the comment was posted, and now you need to use a method provided by a submodule matplotlib.path.

Joe 评论的更新。Matplotlib API 自从评论发布后发生了变化,现在您需要使用 submodule 提供的方法matplotlib.path

Working code is below.

工作代码如下。

import numpy as np
from matplotlib.path import Path

nx, ny = 10, 10
poly_verts = [(1,1), (5,1), (5,9),(3,2),(1,1)]

# Create vertex coordinates for each grid cell...
# (<0,0> is at the top left of the grid in this system)
x, y = np.meshgrid(np.arange(nx), np.arange(ny))
x, y = x.flatten(), y.flatten()

points = np.vstack((x,y)).T

path = Path(poly_verts)
grid = path.contains_points(points)
grid = grid.reshape((ny,nx))

print grid

回答by Alpha

As a slight alternative to @Yusuke N.'sanswer, consider using matplotlib.path, which is just as efficient as the one by from PIL import Image, ImageDraw(no need to install Pillow, no need to consider integeror float. Useful me?)

作为@Yusuke N.答案的一个小替代方案,请考虑使用matplotlib.path,它与 one by 一样有效from PIL import Image, ImageDraw(无需安装Pillow,无需考虑integerfloat。对我有用吗?)

Working code is below:

工作代码如下:

import pylab as plt
import numpy as np
from matplotlib.path import Path

width, height=2000, 2000

polygon=[(0.1*width, 0.1*height), (0.15*width, 0.7*height), (0.8*width, 0.75*height), (0.72*width, 0.15*height)]
poly_path=Path(polygon)

x, y = np.mgrid[:height, :width]
coors=np.hstack((x.reshape(-1, 1), y.reshape(-1,1))) # coors.shape is (4000000,2)

mask = poly_path.contains_points(coors)
plt.imshow(mask.reshape(height, width))
plt.show()

And the result image is below, where dark areais False, bright areais True. enter image description here

结果图像如下,其中暗区False亮区True在此处输入图片说明