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
SciPy Create 2D Polygon Mask
提问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,无需考虑integer或float。对我有用吗?)
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.


