我搜索了很多,无法找到我的问题的任何实际答案。我有一个多边形。例如:
[(86, 52), (85, 52), (81, 53), (80, 52), (79, 48), (81, 49), (86, 53),
(85, 51), (82, 54), (84, 54), (83, 49), (81, 52), (80, 50), (81, 48),
(85, 50), (86, 54), (85, 54), (80, 48), (79, 50), (85, 49), (80, 51),
(85, 53), (82, 49), (83, 54), (82, 53), (84, 49), (79, 49)]
我想获得此边框多边形内所有点的列表。我听说很多关于多边形三角测量技术或线性/泛光/交叉/ ......填充算法。但我真的想出一个有效的方法来实现这一点。这个多边形很小,想象一个有10亿个点的多边形。我现在使用PIL绘制多边形用红色填充多边形并在其中循环以找到红点。这是一种非常缓慢的技术:
def render(poly, z):
xs = [i[0] for i in poly]
ys = [i[1] for i in poly]
minx, maxx = min(xs), max(xs)
miny, maxy = min(ys), max(ys)
X = maxx - minx + 1
Y = maxy - miny + 1
newPoly = [(x - minx, y - miny) for (x, y) in polygons]
i = Image.new("RGB", (X, Y))
draw = ImageDraw.Draw(i)
draw.polygon(newPoly, fill="red")
# i.show()
tiles = list()
w, h = i.size
print w, h
for x in range(w):
for y in range(h):
data = i.getpixel((x, y))
if data != (0, 0, 0):
tiles.append((x + minx, y + miny))
return tiles
我正在寻找一种解决这个问题的Pythonic方法。 谢谢大家。
答案 0 :(得分:7)
我建议使用matplotlib Fiddle Link
from matplotlib.path import Path
tupVerts=[(86, 52), (85, 52), (81, 53), (80, 52), (79, 48), (81, 49), (86, 53),
(85, 51), (82, 54), (84, 54), (83, 49), (81, 52), (80, 50), (81, 48),
(85, 50), (86, 54), (85, 54), (80, 48), (79, 50), (85, 49), (80, 51),
(85, 53), (82, 49), (83, 54), (82, 53), (84, 49), (79, 49)]
x, y = np.meshgrid(np.arange(300), np.arange(300)) # make a canvas with coordinates
x, y = x.flatten(), y.flatten()
points = np.vstack((x,y)).T
p = Path(tupVerts) # make a polygon
grid = p.contains_points(points)
mask = grid.reshape(300,300) # now you have a mask with points inside a polygon
答案 1 :(得分:2)
我认为绘制多边形并填充它是一个很好的开始,无论如何你都需要类似的东西,这些算法通常都是用C调整的。但是不要使用RGB图像,使用黑/白图像,并使用numpy.where()
查找其为1的像素。
根据this question,mahotas
库有fill_polygon
函数,可以使用numpy数组。
我从你的函数开始以下代码(我会减去minx
和maxx
但是请注意我根本无法测试它,我不在我的开发中机。
import numpy as np
import mahotas
def render(poly): # removed parameter 'z'
xs = [i[0] for i in poly]
ys = [i[1] for i in poly]
minx, maxx = min(xs), max(xs)
miny, maxy = min(ys), max(ys)
X = maxx - minx + 1
Y = maxy - miny + 1
newPoly = [(x - minx, y - miny) for (x, y) in poly]
grid = np.zeros((X, Y), dtype=np.int8)
mahotas.polygon.fill_polygon(newPoly, grid)
return [(x + minx, y + miny) for (x, y) in np.where(grid)]
答案 2 :(得分:2)
您可以使用像二进制图像这样的numpy矩阵,可以与Opencv或其他图像处理库一起使用, 解决方案1 所以矩阵的大小为L x H,其中
L=max(x) - min (x)
H=max(y) - min (y)
作为条目我们有你的元组(x,y)列表,你在上面给出的名称是 poly ,例如:
import numpy as np
matrix =np.zeros((L,H),dtype=np.int32) # you can use np.uint8 if unsigned x ,y
所以我们现在有一个填充0的大小为L x H的矩阵,我们现在将1放在多边形位置
我认为你可以简单地做到这一点
matrix[poly]=1 # which will put 1 at each (x,y) of the list **poly**
我们将其解释为二进制(黑/白)图像,其上绘制有轮廓 假设我们想要检测这个新轮廓
import cv2 # opencv import
ContoursListe,hierarchy = cv2.findContours(self.thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
poly2=ContoursListe[0] # we take the first only contour
注意: poly2 包含多边形的点列表以及形成它的所有点,我的意思是您需要的多边形的每个顶点的所有点都可以找到有用的 !您可以使用 cv2.CHAIN_APPROX_SIMPLE 参数来获取仅包含多边形线的端点的poly2,这些端点更轻,这是我们的输入:) 重要:poly2的类型是numpy数组,其形状为(n,1,2)而不是(n,2)
现在我们在这个图像(矩阵)上绘制这个轮廓并填充它:)
cv2.drawContours(matrix,[poly2],-1,(1),thickness=-1)
thickness=-1
现在我们有一个矩阵,其中每个点上有 1 形成并填充多边形,“thickness = -1”已强制填充此轮廓,可以设置厚度= 1来获取只有边界 如果你想翻译,你可以通过添加参数偏移(xtran,ytrans)
来实现获取所有这些点的索引只需调用
list_of_points_indices=numpy.nonzero(matrix)
解决方案2
更聪明的是直接将点列表(poly)转换为轮廓格式(poly2)并将其绘制在矩阵上
poly2=poly.reshape(-1,1,2).astype(np.int32)
并在Matrix矩阵上绘制
matrix =np.zeros((L,H),dtype=np.int32)
cv2.drawContours(matrix,[poly2],-1,(1),thickness=-1)
并获得以下列表:
list_of_points_indices=numpy.nonzero(matrix)
使用厚度来填充或不填充多边形,有关更多详细信息,请参阅解决方案1.
答案 3 :(得分:1)
基于RemcoGerlich的答案,这是一个经过验证的功能:
import numpy as np
import mahotas
def render(poly):
"""Return polygon as grid of points inside polygon.
Input : poly (list of lists)
Output : output (list of lists)
"""
xs, ys = zip(*poly)
minx, maxx = min(xs), max(xs)
miny, maxy = min(ys), max(ys)
newPoly = [(int(x - minx), int(y - miny)) for (x, y) in poly]
X = maxx - minx + 1
Y = maxy - miny + 1
grid = np.zeros((X, Y), dtype=np.int8)
mahotas.polygon.fill_polygon(newPoly, grid)
return [(x + minx, y + miny) for (x, y) in zip(*np.nonzero(grid))]
示例:强>
poly = [
[0, 0],
[0, 10],
[10, 10],
[10, 0]
]
plt.figure(None, (5, 5))
x, y = zip(*render(poly))
plt.scatter(x, y)
x, y = zip(*poly)
plt.plot(x, y, c="r")
plt.show()
答案 4 :(得分:0)
试试这段代码。 poly_coords是多边形的坐标,' coord'是要检查它是否在多边形内的点的坐标。
def testP(coord, poly_coords):
"""
The coordinates should be in the form of list of x and y
"""
test1 = n.array(poly_coords)
test2 = n.vstack((poly_coords[1:], poly_coords[:1]))
test = test2-test1
m = test[:,1]/test[:,0]
c = test1[:,1]-m*test1[:,0]
xval = (coord[1]-c)/m
print 'xVal:\t'; print xval
print (test1[:,0]-xval)*(test2[:,0]-xval)
check = n.where((xval>=coord[0])&((test1[:,0]-xval)*(test2[:,0]-xval)<0))[0]
print check
print len(check)
if len(check)%2==0:
return False
else:
return True
如果你想让它更快,请取出与多边形,斜率和偏移相关的算法部分,然后使用&#39; map&#39;运行剩下的代码。功能。像这样:
test1 = n.array( your polygon)
test2 = n.vstack((test1[1:], test1[:1]))
test = test2-test1
m = test[:,1]/test[:,0]
c = test1[:,1]-m*test1[:,0]
def testP(coord):
"""
The coordinates should be in the form of list of x and y
"""
global test, test1, test2, m,c
xval = (coord[1]-c)/m
check = n.where((xval>=coord[0])&((test1[:,0]-xval)*(test2[:,0]-xval)<0))[0]
if len(check)%2==0:
return False
else:
return True
coords = n.array(( your coords in x,y ))
map (testP, coords)
您可以删除&#39; print&#39;命令,如果你想。此代码适用于python 2.7