在 numpy 数组中生成填充的多边形
Generating a filled polygon inside a numpy array
我正在寻找一种方法,可以根据一组多边形顶点 'draw' 将填充的多边形转换为 numpy 数组。我宁愿使用尽可能少的外部库。
例如:我有一个 20x20 的 numpy 数组,我想要由点 (3,12)、(8,18)、(13,14)、(11,6) 和 (4) 界定的区域,6) 用 1.0 填充,而数组的其余部分包含 0.0
以下解决方案只需要 numpy。它适用于凸多边形的顶点(在 [Row, Column] 坐标系中按顺时针顺序定义)。凹多边形可以,但最终会切断突出点。
import numpy as np
def check(p1, p2, base_array):
"""
Uses the line defined by p1 and p2 to check array of
input indices against interpolated value
Returns boolean array, with True inside and False outside of shape
"""
idxs = np.indices(base_array.shape) # Create 3D array of indices
p1 = p1.astype(float)
p2 = p2.astype(float)
# Calculate max column idx for each row idx based on interpolated line between two points
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
sign = np.sign(p2[0] - p1[0])
return idxs[1] * sign <= max_col_idx * sign
def create_polygon(shape, vertices):
"""
Creates np.array with dimensions defined by shape
Fills polygon defined by vertices with ones, all other values zero"""
base_array = np.zeros(shape, dtype=float) # Initialize your array of zeros
fill = np.ones(base_array.shape) * True # Initialize boolean array defining shape fill
# Create check array for each edge segment, combine into fill array
for k in range(vertices.shape[0]):
fill = np.all([fill, check(vertices[k-1], vertices[k], base_array)], axis=0)
# Set all values inside polygon to one
base_array[fill] = 1
return base_array
# (Row, Col) Vertices of Polygon (Defined Clockwise)
vertices = np.array([
[5,12],
[8,18],
[13,14],
[11,6],
[4,6],
])
polygon_array = create_polygon([20,20], vertices)
# This section prints numbers at each vertex for visual check, just comment out
# to print an array of only zeros and ones
for n, vertex in enumerate(vertices):
polygon_array[vertex[0],vertex[1]] = 10*(n+1)
# Simple routine to print the final array
for row in polygon_array.tolist():
for c in row:
print '{:4.1f}'.format(c),
print ''
我在@schoolie 响应中发现了一个错误,Whosebug 不允许在评论中添加多行代码片段,问题出在 p1[0] == p2[0]
时。我对函数更新的建议 check
:
if p1[0] == p2[0]:
max_col_idx = (idxs[0] - p1[0]) * idxs.shape[1]
sign = np.sign(p2[1] - p1[1])
else:
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
sign = np.sign(p2[0] - p1[0])
This example 来自scikits-image
我想可以应用到这个问题。
vertices = np.array([
[5,12],
[8,18],
[13,14],
[11,6],
[4,6],
])
from skimage.draw import polygon
img = np.zeros((20, 20), 'uint8')
rr, cc = polygon(vertices[:,0], vertices[:,1], img.shape)
img[rr,cc] = 1
img.shape
(20, 20)
img.sum()
80
我正在寻找一种方法,可以根据一组多边形顶点 'draw' 将填充的多边形转换为 numpy 数组。我宁愿使用尽可能少的外部库。
例如:我有一个 20x20 的 numpy 数组,我想要由点 (3,12)、(8,18)、(13,14)、(11,6) 和 (4) 界定的区域,6) 用 1.0 填充,而数组的其余部分包含 0.0
以下解决方案只需要 numpy。它适用于凸多边形的顶点(在 [Row, Column] 坐标系中按顺时针顺序定义)。凹多边形可以,但最终会切断突出点。
import numpy as np
def check(p1, p2, base_array):
"""
Uses the line defined by p1 and p2 to check array of
input indices against interpolated value
Returns boolean array, with True inside and False outside of shape
"""
idxs = np.indices(base_array.shape) # Create 3D array of indices
p1 = p1.astype(float)
p2 = p2.astype(float)
# Calculate max column idx for each row idx based on interpolated line between two points
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
sign = np.sign(p2[0] - p1[0])
return idxs[1] * sign <= max_col_idx * sign
def create_polygon(shape, vertices):
"""
Creates np.array with dimensions defined by shape
Fills polygon defined by vertices with ones, all other values zero"""
base_array = np.zeros(shape, dtype=float) # Initialize your array of zeros
fill = np.ones(base_array.shape) * True # Initialize boolean array defining shape fill
# Create check array for each edge segment, combine into fill array
for k in range(vertices.shape[0]):
fill = np.all([fill, check(vertices[k-1], vertices[k], base_array)], axis=0)
# Set all values inside polygon to one
base_array[fill] = 1
return base_array
# (Row, Col) Vertices of Polygon (Defined Clockwise)
vertices = np.array([
[5,12],
[8,18],
[13,14],
[11,6],
[4,6],
])
polygon_array = create_polygon([20,20], vertices)
# This section prints numbers at each vertex for visual check, just comment out
# to print an array of only zeros and ones
for n, vertex in enumerate(vertices):
polygon_array[vertex[0],vertex[1]] = 10*(n+1)
# Simple routine to print the final array
for row in polygon_array.tolist():
for c in row:
print '{:4.1f}'.format(c),
print ''
我在@schoolie 响应中发现了一个错误,Whosebug 不允许在评论中添加多行代码片段,问题出在 p1[0] == p2[0]
时。我对函数更新的建议 check
:
if p1[0] == p2[0]:
max_col_idx = (idxs[0] - p1[0]) * idxs.shape[1]
sign = np.sign(p2[1] - p1[1])
else:
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
sign = np.sign(p2[0] - p1[0])
This example 来自scikits-image
我想可以应用到这个问题。
vertices = np.array([
[5,12],
[8,18],
[13,14],
[11,6],
[4,6],
])
from skimage.draw import polygon
img = np.zeros((20, 20), 'uint8')
rr, cc = polygon(vertices[:,0], vertices[:,1], img.shape)
img[rr,cc] = 1
img.shape
(20, 20)
img.sum()
80