SciPy创建2D多边形蒙版

Isa*_*and 37 python polygon scipy sage point-in-polygon

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

  • 输入:多边形顶点,图像尺寸
  • 输出:多边形的二进制掩码(numpy 2D数组)

(更大的上下文:我想使用scipy.ndimage.morphology.distance_transform_edt获取此多边形的距离变换.)

谁能告诉我怎么做?

Isa*_*and 64

答案结果很简单:

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)
Run Code Online (Sandbox Code Playgroud)

  • 来自:@jmetz“仅供参考:我做了一个简单的时序测试,PIL方法比matplotlib版本快70倍!” (3认同)
  • @DeepakUmredkar如果您的点是浮动的,则将它们四舍五入。无论如何,您的蒙版都应该是二进制的,因此它们必须是像素坐标。 (3认同)
  • 我认为这种方法只适用于整数坐标(即网格坐标).如果顶点坐标是浮点数,则另一个解决方案仍然有效. (2认同)
  • 对于未来的访问者来说可能有用:多边形列表的方向顺序似乎并不重要。它总是会给内部着色。您可以将它们以顺时针或逆时针的方式插入。只需确保与此选择一致 - 极角应严格增加或减少(混合坐标对应于数学上不同的多边形)。 (2认同)

Joe*_*ton 25

作为@Anil答案的一个更直接的替代品,matplotlib matplotlib.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
Run Code Online (Sandbox Code Playgroud)

产生(布尔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]]
Run Code Online (Sandbox Code Playgroud)

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

  • 仅供参考:我做了一个简单的计时测试,而且'PIL`方法比`matplotlib`版本快了〜******! (7认同)
  • @Issac - 够公平的。据我所知,PIL 不使用任何类型的硬件加速,但是......(最近有变化吗?)此外,如果您使用 PIL,则无需执行`M = numpy.reshape(list(img) .getdata()), (height, width)))`,正如您在上面的评论中提到的。`numpy.array(img)` 做同样的事情,效率更高。 (2认同)
  • 远!感谢您指出 numpy.array(img) 功能。而且,确实,PIL 可能仍然不使用硬件加速。 (2认同)

小智 13

Joe的评论更新.自评论发布以来,Matplotlib API已发生变化,现在您需要使用子模块提供的方法matplotlib.path.

工作代码如下.

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
Run Code Online (Sandbox Code Playgroud)


小智 11

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

工作代码如下:

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()
Run Code Online (Sandbox Code Playgroud)

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