Python:非凸网格的边界点

时间:2018-03-05 13:10:37

标签: python numpy

我有以下情况,如下图所示:

enter image description here

我想找出红点周围的网格点。红点是移动代理的轨迹。因此,在许多情况下,我们有一堆点,因此解决方案应尽可能

网格绘制为点。

  • 第一步,我设法减少了网格点的数量,如下所示(标记为x):

enter image description here

这是我的代码:

step = .5
gridX, gridY = np.meshgrid(np.arange(xmin-step, xmax+step, step), np.arange(ymin-step, ymax+step, step))
mask = False * np.empty_like(gridX, dtype=bool)
threshold = 0.5
for (x,y) in  zip(df_traj['X'], df_traj['Y']):
    pX = x * np.ones_like(gridX)
    pY = y * np.ones_like(gridY)
    distX = (pX - gridX)**2
    distY = (pY - gridY)**2
    dist = np.sqrt(distX + distY)
    condition = (dist < threshold)
    mask = mask | condition

gX = gridX*mask
gY = gridY*mask
  • 第二步,这是我需要一点帮助的地方:

如何有效滤除网格的内部点并仅保留&#34; x-points&#34;在&#34;红色区域之外&#34;?

修改

在这个特殊情况下,我有92450个红点。

4 个答案:

答案 0 :(得分:2)

我想如果你只是走在边缘,因为它是一个均匀间隔的网格,它应该工作。不需要更复杂的非凸壳来处理可以在任何地方的支撑。这不适合你的代码,我欺骗我的数据结构,使代码容易,所以你必须处理它,但它认为它应该工作的伪代码。

pnts = <<lists of points>>
edge_pnts = []
fpnt = pnt_with_min_x_then_min_y
cpnt = fpnt
npnt = None 

while npnt != fpnt:

    if   (cpnt[0] + 1, cpnt[1]    ) in pnts: npnt = (cpnt[0] + 1, cpnt[1]    )
    elif (cpnt[0] + 1, cpnt[1] + 1) in pnts: npnt = (cpnt[0] + 1, cpnt[1] + 1)
    elif (cpnt[0],     cpnt[1] + 1) in pnts: npnt = (cpnt[0]    , cpnt[1] + 1)
    elif (cpnt[0] - 1, cpnt[1] + 1) in pnts: npnt = (cpnt[0] - 1, cpnt[1] + 1)
    elif (cpnt[0] - 1, cpnt[1]    ) in pnts: npnt = (cpnt[0] - 1, cpnt[1]    )
    elif (cpnt[0] - 1, cpnt[1] - 1) in pnts: npnt = (cpnt[0] - 1, cpnt[1] - 1)
    elif (cpnt[0]    , cpnt[1] - 1) in pnts: npnt = (cpnt[0]    , cpnt[1] - 1)
    elif (cpnt[0] + 1, cpnt[1] - 1) in pnts: npnt = (cpnt[0] + 1, cpnt[1] - 1)
    else: raise ValueError("Oh no!")

    edge_pnts.append(npnt)
    cpnt = npnt

答案 1 :(得分:1)

你只需要选择一个你知道在船体上的一个点(让我们把最左边的点放在最顶点之间),然后假设你已经到达了它的位置&#34;从上面(我们知道上面没有任何要点)。 现在,而下一个点不在您的列表中:

尝试从你来自的方向开始CCW。

代码如下:

matrix = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
         [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
         [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

# Find the leftmost topmost point
first_point = None
for i in range(len(matrix)):
    if first_point:
        break
    for j in range(len(matrix[0])):
        if matrix[i][j]:
            first_point = [i, j]
            break

next_point = first_point
prev_direction = 'up'
next_direction_dict = {'up': 'left', 'left': 'down', 'down': 'right', 'right': 'up'}
opposite_direction = {'up': 'down', 'left': 'right', 'down': 'up', 'right': 'left'}
hull_points = []


def go_direction(point, direction):
    # Find the point to a given direction of a given point
    i = point[0]
    j = point[1]
    if direction == 'right':
        j += 1
    elif direction == 'up':
        i -= 1
    elif direction == 'left':
        j -= 1
    elif direction == 'down':
        i += 1
    else:
        raise ValueError
    return [i, j]


def find_next_point(matrix, point, prev_direction):
    next_direction = next_direction_dict[prev_direction]
    next_point = go_direction(point, next_direction)
    prev_direction = next_direction
    while not matrix[next_point[0]][next_point[1]]:
        next_direction = next_direction_dict[prev_direction]
        next_point = go_direction(point, next_direction)
        prev_direction = next_direction
    from_direction = opposite_direction[prev_direction]
    return next_point, from_direction

next_point, prev_direction = find_next_point(matrix, next_point, prev_direction)
while next_point != first_point:
    if next_point not in hull_points:
        hull_points.append(next_point)
    next_point, prev_direction = find_next_point(matrix, next_point, prev_direction)

修改 现在还处理单点触角&#39;通过迭代直到返回第一个点

答案 2 :(得分:1)

对于非convex polygons,与您的示例一样,convex hull不是解决方案。我的建议是,鉴于您已经有一个离散网格,当样本发生在内部时,您只需将值False归因于bool网格单元格。像这样:

import numpy as np
import matplotlib.pyplot as plt

# Generic data production
X, Y = np.random.normal(0, 1, 100000), np.random.normal(0, 1, 100000)
ind = np.where((X > 0) & (Y > 0))
X[ind] = 0
Y[ind] = 0    

# Generic grid definition
step  = 0.5
xmin, xmax = X.min(), X.max()
ymin, ymax = Y.min(), Y.max()
firstx = xmin-step/2
firsty = ymin-step/2
lastx  = xmax+2*step/2
lasty  = ymax+2*step/2
gridX, gridY = np.meshgrid(np.arange(firstx, lastx, step), np.arange(firsty, lasty, step))

# This is the actual code that computes inside or outside
bool_grid = np.ones(gridX.shape, dtype="bool")
bool_grid[np.int_(0.5+(Y-firsty)/step), np.int_(0.5+(X-firstx)/step)] = False

# Plot code
plt.scatter(gridX.flatten(), gridY.flatten(), marker="+", color="black", alpha=0.3)
plt.scatter(gridX[bool_grid].flatten(), gridY[bool_grid].flatten(), marker="+", s=90, color="green")
plt.scatter(X, Y, s=10, color="red")
plt.show()

,结果如下(绿色十字是True值):

enter image description here

注意:这是非常快的,但它有一些限制。 如果您的数据不紧凑,您将在形状中包含 True 值(因此可能存在漏洞)。然而,可以处理图像以移除孔(例如,填充填充或基于移动窗口的算法)。另一种可能性是使用网格的分辨率。

答案 3 :(得分:0)

虽然我想到了另一个人 -

空间的洪水填充:

pnts = <<lists of points>>
seen = set()
edges = []
stack = (0,0)

while stack:
    ele = stack.pop()
    if ele in pnts:
        edges.append(ele)
    else:
        seen.add(ele)
        if (ele[0] + 1, ele[1]) not in seen: 
            stack.append(ele[0] + 1, ele[1])
        if (ele[0] - 1, ele[1]) not in seen: 
            stack.append(ele[0] - 1, ele[1])
        if (ele[0], ele[1] + 1) not in seen: 
            stack.append(ele[0], ele[1] + 1)
        if (ele[0], ele[1] - 1) not in seen: 
            stack.append(ele[0], ele[1] - 1)

然后你需要对那些不应该太难的点进行排序。