【问题标题】:Generate coordinates inside Polygon在 Polygon 内生成坐标
【发布时间】:2013-03-07 00:46:18
【问题描述】:

我想将多边形的值合并到一个精细的规则网格中。 例如,我有以下坐标:

data = 2.353
data_lats = np.array([57.81000137,  58.15999985,  58.13000107,  57.77999878])
data_lons = np.array([148.67999268,  148.69999695,  148.47999573,  148.92999268])

我的常规网格如下所示:

delta = 0.25
grid_lons = np.arange(-180, 180, delta)
grid_lats = np.arange(90, -90, -delta)
llx, lly = np.meshgrid( grid_lons, grid_lats )
rows = lly.shape[0]
cols = llx.shape[1]
grid = np.zeros((rows,cols))

现在我可以很容易地找到对应于多边形中心的网格像素:

centerx, centery = np.mean(data_lons), np.mean(data_lats)
row = int(np.floor( centery/delta ) + (grid.shape[0]/2))
col = int(np.floor( centerx/delta ) + (grid.shape[1]/2))
grid[row,col] = data

但是,可能有几个网格像素仍与多边形相交。因此,我想在我的多边形(data_lons,data_lats)内生成一堆坐标,并像以前一样找到它们对应的网格像素。您是否建议随机或系统地生成坐标?我失败了,但我还在努力。

注意:一个数据集包含大约 80000 个多边形,因此它必须非常快(几秒钟)。这也是我选择这种方法的原因,因为它没有考虑重叠区域......(就像我之前的问题Data binning: irregular polygons to regular mesh 非常慢)

【问题讨论】:

  • 看看你之前的问题,它有一个有用的数字来显示比例,似乎每个网格像素都应该与一个多边形相关联,在这种情况下,你可以找到网格像素的中心,并将其与最近的多边形中心相关联。
  • 这是一个很好的观点。不幸的是,一些多边形共享是网格像素的很大一部分,因此我取它们的平均值。我上面没有提到的是,我将落入一个网格像素的所有值相加,然后从总数中取平均值。我认为这更现实一些。
  • 只是忘了...通过为每个网格像素找到最近的多边形中心,计算应该会显着提高吗?所以我认为最好反过来。
  • 我不是专家,但我认为匹配距离比计算重叠要快得多。我在我的研究中做了类似的事情,它并不太慢,但我只有大约 1k 个粒子。
  • 我肯定会更多地研究使用距离,也许我弄错了。虽然,目前上述代码并未计算任何重叠。到目前为止,它只需要 1 秒,因为它只是分配值。此外,多边形看起来不像正方形,因此中心可能比其他边更靠近某些边。

标签: python numpy


【解决方案1】:

我通过简单地计算角像素之间的坐标来制定一个快速而肮脏的解决方案。看看:

dlats = np.zeros((data_lats.shape[0],4))+np.nan
dlons = np.zeros((data_lons.shape[0],4))+np.nan
idx = [0,1,3,2,0] #rearrange the corner pixels

for cc in range(4):
    dlats[:,cc] = np.mean((data_lats[:,idx[cc]],data_lats[:,idx[cc+1]]), axis=0)
    dlons[:,cc] = np.mean((data_lons[:,idx[cc]],data_lons[:,idx[cc+1]]), axis=0)

data_lats = np.column_stack(( data_lats, dlats ))
data_lons = np.column_stack(( data_lons, dlons ))

因此,红点代表原始角点 - 蓝色点代表它们之间的中间像素。

我可以再做一次,包括中心像素 (geo[:,[4,9]])

dlats = np.zeros((data.shape[0],8))
dlons = np.zeros((data.shape[0],8))

for cc in range(8):
    dlats[:,cc] = np.mean((data_lats[:,cc], geo[:,4]), axis=0)
    dlons[:,cc] = np.mean((data_lons[:,cc], geo[:,9]), axis=0)

data_lats = np.column_stack(( data_lats, dlats, geo[:,4] ))
data_lons = np.column_stack(( data_lons, dlons, geo[:,9] ))

这真的很好用,我可以像这样将每个点直接分配给它对应的网格像素:

row = np.floor( data_lats/delta ) + (llx.shape[0]/2)
col = np.floor( data_lons/delta ) + (llx.shape[1]/2)

然而,最后的分箱现在需要大约 7 秒!!!我怎样才能加快这段代码的速度:

for ii in np.arange(len(data)):
    for cc in np.arange(data_lats.shape[1]):
        final_grid[row[ii,cc],col[ii,cc]] += data[ii]
        final_grid_counts[row[ii,cc],col[ii,cc]] += 1

【讨论】:

  • 为了清洁,您应该接受自己的答案并将其作为新问题发布。我没有详细查看您的代码,但是 for 循环太多了,因为它无法得到很大的改进。
【解决方案2】:

您需要测试以下方法,看看它是否足够快。首先,您应该将所有 lats 和 lons 修改为,以使它们(可能是分数)索引到您的网格中:

idx_lats = (data_lats - lat_grid_start) / lat_grid step
idx_lons = (data_lons - lon_grid_start) / lon_grid step

接下来,我们要将多边形分割成三角形。对于任何凸多边形,您可以将多边形的中心作为所有三角形的一个顶点,然后将多边形的顶点连续成对。但是如果你的多边形都是四边形,那么将它们分成两个三角形会更快,第一个使用顶点 0、1、2,第二个使用顶点 0、2、3。

要知道某个点是否在三角形内,我将使用here 中描述的重心坐标方法。第一个函数检查一堆点是否在三角形内:

def check_in_triangle(x, y, x_tri, y_tri) :
    A = np.vstack((x_tri[0], y_tri[0]))
    lhs = np.vstack((x_tri[1:], y_tri[1:])) - A
    rhs = np.vstack((x, y)) - A
    uv = np.linalg.solve(lhs, rhs)
    # Equivalent to (uv[0] >= 0) & (uv[1] >= 0) & (uv[0] + uv[1] <= 1)
    return np.logical_and(uv >= 0, axis=0) & (np.sum(uv, axis=0) <= 1)

给定一个三角形的顶点,您可以通过对三角形边界框中的格点运行上述函数来获取其中的格点:

def lattice_points_in_triangle(x_tri, y_tri) :
    x_grid = np.arange(np.ceil(np.min(x_tri)), np.floor(np.max(x_tri)) + 1)
    y_grid = np.arange(np.ceil(np.min(y_tri)), np.floor(np.max(y_tri)) + 1)
    x, y = np.meshgrid(x_grid, y_grid)
    x, y = x.reshape(-1), y.reshape(-1)
    idx = check_in_triangle(x, y, x_tri, y_tri)
    return x[idx], y[idx]

对于四边形,您只需调用最后一个函数两次:

def lattice_points_in_quadrilateral(x_quad, y_quad) :
    return map(np.concatenate,
               zip(lattice_points_in_triangle(x_quad[:3], y_quad[:3]),
                   lattice_points_in_triangle(x_quad[[0, 2, 3]],
                                              y_quad[[0, 2, 3]])))

如果您对示例数据运行此代码,您将返回两个空数组:这是因为四边形点的顺序令人惊讶:索引 0 和 1 定义一个对角线,2 和 3 定义另一个。我上面的函数期望顶点围绕多边形排序。如果您真的以其他方式做事,则需要将第二次调用更改为 lattice_points_in_trianglelattice_points_in_quadrilateral 以便使用的索引是 [0, 1, 3] 而不是 [0, 2, 3]

现在,有了这个改变:

>>> idx_lats = (data_lats - (-180) ) / 0.25
>>> idx_lons = (data_lons - (-90) ) / 0.25
>>> lattice_points_in_quadrilateral(idx_lats, idx_lons)
[array([952]), array([955])]

如果您将网格的分辨率更改为 0.1:

>>> idx_lats = (data_lats - (-180) ) / 0.1
>>> idx_lons = (data_lons - (-90) ) / 0.1
>>> lattice_points_in_quadrilateral(idx_lats, idx_lons)
[array([2381, 2380, 2381, 2379, 2380, 2381, 2378, 2379, 2378]),
 array([2385, 2386, 2386, 2387, 2387, 2387, 2388, 2388, 2389])]

在我的系统中,这种方法对于您的需求来说会慢 10 倍左右:

In [8]: %timeit lattice_points_in_quadrilateral(idx_lats, idx_lons)
1000 loops, best of 3: 269 us per loop

所以您正在查看超过 20 秒。处理您的 80,000 个多边形。

【讨论】:

  • 非常感谢您的详细解答!我绝对可以从中学习!不过,运行时间让我有点担心,因为在我的情况下,此类卫星像素的合并应该是超快的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-16
相关资源
最近更新 更多