基于 Python 的自然邻域法空间插值的实现与优化

  接上期基于 Python 的自然邻域法空间插值的实现与思考。

  上期说到,我们仅仅利用自然邻域法基础原理进行插值,会出现许多空值、异常值,且与ArcGIS相同分辨率、范围下的插值结果对比(对比图如下),结果较差。主要体现在:

  1. 插值结果范围内有空值,而ArcGIS没有,可能是ArcGIS做了其他的一些处理。
  2. ArcGIS插值结果仅包含了最外层点组成的面内的数据,显然,边界外的数据插值结果异常值较多
  3. 部分区域插值结果较差(例如下图左,左下角),仍有需要改进的地方

基于 Python 的自然邻域法空间插值的实现与优化_第1张图片

  后续优化实践过程中遇到了瓶颈,偶然机会发现可能是泰森多边形构建的问题,主要问题在于:泰森多边形存在无限区域,导致后续加权计算时面积异常。无限区域因为缺少顶点因此无法形成多边形!
基于 Python 的自然邻域法空间插值的实现与优化_第2张图片
  解决的方法也比较容易理解,就是有效化泰森多边形无限区域。经过尝试,基本解决上述问题。达到了函数构建的预期效果。主要解决的内容如下:

有效化泰森多边形无限区域

  有效化方法如下,有需要可以学习参考。

# 饮用

def VoronoiVertices(Points):
    """
    生成泰森多边形标记(区域序号,多边形点端点位置,端点数组,无限区域序号),并使无限区域有限。
    """   
    
    VOR = Voronoi(Points, incremental = True)
    Vertices = VOR.vertices
    
    # NewRegions = []
    NewVertices = Vertices.copy()
    
    # 几何中心和半径
    Center = Points.mean(axis=0)
    Radius = Points.ptp().max() * 2
    
    # 构建包含给定点的所有脊    
    AllRidges = {}
    RidgePoints = VOR.ridge_points
    RidgeVertices = VOR.ridge_vertices
    for p1, p2, v1, v2 in np.concatenate([RidgePoints, RidgeVertices], axis = 1):
        AllRidges.setdefault(p1, []).append((p2,v1,v2))
        AllRidges.setdefault(p2, []).append((p1,v1,v2))
        
    # 重构无限区域
    PointRegion = VOR.point_region
    Regions = VOR.regions[:]
    
    # 记录无限区域,方便提取边界
    InfiniteRegion = []

    for p1, pr in enumerate(PointRegion):
        Vertice = np.array(Regions[pr])
        
        # 跳过正常区域
        if (Vertice != -1).all() and Vertice.size != 0:
            continue
        Ridges = AllRidges[p1]
        NewRegion = Vertice[Vertice != -1]
 
        for p2, v1, v2 in Ridges:
            if v2 < 0:
                v1, v2 = v2, v1
            if v1 >= 0:
                # 有限脊:已在该区域
                continue

            # 计算无限脊的缺失端点
            T = Points[p2] - Points[p1] # 切线
            T /= np.linalg.norm(T)
            n = np.array([-T[1], T[0]])  # 正常

            MidPoint = Points[[p1, p2]].mean(axis=0)
            Direction = np.sign(np.dot(MidPoint - Center, n)) * n
            FarPoint = Vertices[v2] + Direction * Radius

            NewRegion = np.append(NewRegion, len(NewVertices))

            NewVertices = np.append(NewVertices, [FarPoint], axis = 0)
            
        # 更新 
        Regions[pr] = list(NewRegion)
        # 记录无限区域点
        InfiniteRegion.append(p1)

    return PointRegion, Regions, NewVertices, InfiniteRegion

新的泰森多边形

基于 Python 的自然邻域法空间插值的实现与优化_第3张图片

更新后的插值结果对比

总结

  插值结果用插值点组成的最大外部多边形裁剪之后与ArcGIS结果几乎一致,满足精度需求。
  算法缺点:插值速度较慢。

你可能感兴趣的:(地理与气象分析库,地理数据与处理,python)