ArcGIS分水岭工具使用什么算法?


10

有谁知道ArcGIS分水岭工具(在Spatial Analyst软件包中)使用哪种算法?

Esri网站上提供的信息很少...但是我怀疑这可能是某种深度/广度搜索。

我查看了以下ArcGIS Online帮助页面:

是的,它使用流向栅格,但是遍历栅格使用什么算法?

请注意,我并不是在寻找“它使用D8 ..”的答案。...D8并不是真正的算法,而是可以帮助定义您将要使用的算法的模型。IE,您可以在深度优先搜索算法和/或广度优先搜索算法中实施D8方案


詹姆斯,我正在尝试做同样的事情,即创建一个应用程序,该应用程序具有确定的坐标并为我们提供分水岭的轮廓。我正在使用python。让我们谈谈我们的进步。

我也在使用Python。我从计算流向网格并从那里继续前进的简单问题开始。
詹姆斯

Answers:


6

我已经用几种语言实现并相信ESRI使用的方法(对不起,除此页其他地方引用的Jenson和Domingue之外,没有其他参考)是从用户提供的“倾点”单元或一个单元开始的在流向网格(fdr)的边缘,检查其八个邻居,以找出哪些直接流进当前单元格,并将这些单元格分配到输出网格中的当前“分水岭”。然后,该函数为每个流入的邻居递归调用一次。重复此过程,直到所有流入的池都用完了一个倾点为止,然后对所有倾点重复一次。

递归算法设计可能会非常昂贵,因为它最终可能会试图在内存中保存大量数据,不得不交换/分页到磁盘,因此通常会遭受I / O速度降低的麻烦。

(如果要使用RYO,请参见下面关于不同的递归方法的wuber的评论)

_____________ 编辑 _____________

挖出我的旧C代码作为示例(注意:尽管大多数pythoner可能想从房间运行,但应该不会太糟)。认为可能需要说明。尽管我现在才刚刚肤浅地熟悉w / breadth-first vs depth-first递归,但基于此stackoverflow发布(希望@或比我聪明的人可以确认/拒绝)。

代码:说明:idir是流向值的栅格。offset指当前正在分析的中心单元,并off检查该单元的每个邻居。这将调用另一个函数,does_it_flow_into_me该函数返回有关相邻单元格的flowdir是否指向当前单元格的布尔值。如果对邻居为true,则递归到该位置。

void shed(int init_x, int init_y, int basin_id){

int i, j, offset, off, flow_dir;

offset = ((init_y - 1) * nc) + (init_x - 1);
*(basin + offset) = basin_id;


/* kernel analysis */
for (i = -1; i <  2; i++) {
    for (j = -1; j <  2; j++) {
        if ((i) || (j)) {

            off = offset + (j * nc +  i);
            flow_dir = *(idir + off);


            if (does_it_flow_into_me(i,j,flow_dir)){
                shed(init_x+i, init_y+j,basin_id);
            }
        } /*not center */
    } /* do - j */
} /* do - i */
}

您描述了广度优先的递归。通过一个小的堆栈,您可以实现高效的深度优先递归,这需要很少的内存。主要的性能问题将涉及大型分水岭,在该分水岭中,网格图块可能不得不反复换入和换出RAM。但是,正如在对其他答案的评论中所讨论的那样,真正的问题在于如何处理没有唯一确定的D8方向的单元格,尤其是位于广泛的平坦水平斑块(例如由初步的水槽填充程序创建的那些)之内的单元格。
ub

绝对是垃圾入垃圾的问题。我和大多数GI所做的事情不会清除输入内容!听起来,我需要先进行深度优先递归,以进一步完善自己的技巧。
罗兰

我不认为这是垃圾-记住,无论如何分解实现,原始输入都是DEM本身,而不是某人的D8编码-但这绝对是一个挑战。现实世界中有很多地方是如此平坦,以至于很难确定流向:任何静态水体都是一个很好的例子。实际上,您需要找到湖泊和其他平坦区域的出口,并且需要应对具有多个出口的平坦区域。这需要非本地搜索,这很难做到。
ub

那我可能很困惑。我认为我们正在讨论help.arcgis.com/en/arcgisdesktop/10.0/help../index.html#//…,它以flowdir作为输入。如果我还没有足够仔细地阅读其余内容,不想让我们陷入困境!
罗兰

不,我认为您是对的:当我重新阅读该问题时,我看到它特别关注于处理流向栅格作为输入,而不是我所设想的更一般的情况。因此,对您的答案+1,以直接解决问题,并提供有见识和有益的指导。
ub

4

ArcGIS的帮助说:

通过计算流向并在分水岭工具中使用它,可以从DEM划定分水岭。为了确定贡献区域,必须首先使用“流向”工具创建代表流向的栅格。

流动方向是使用D8方法DEM计算得出的,其中,通过计算每个单元的水量来抽象流,该单元是8个邻居中的哪个,该单元中的水将流向该单元。

D8有许多替代方案,例如Rho8,Froh8和Stream Tubes,但是大多数GIS软件(包括ArcGIS)都倾向于使用D8,因为它比其他方法更简单且计算量更少。


几年前,我正在进行“分水岭划界”项目,由于ArcGIS使用D8方法,我们遇到了一些问题。两个主要问题是

  • D8仅允许单向流。水只能从一个单元向一个方向流出。
  • 产生的水流沿对角线轴具有很大的偏差。这引起了奇怪的流。

根据我们的数据,我们知道这两个问题是大问题,因此我开发了一些工具来使用混合方法生成流向。

我最早的任务之一是对流域计算工具进行逆向工程。我发现从逻辑上讲它很简单。如果要查找给定点(也称为倾泻点)的汇水面积,首先要找到其所属的单元。通常,您将尝试在给定的公差范围内将其捕捉到具有最高流量累积的点。

对于此单元格,您将找到附近所有对其有贡献的单元格。对于这些邻近单元中的每一个,您都会找到对它们有贡献的单元,依此类推。您将继续执行此迭代过程,直到找不到新的单元格为止。那是当您到达山脊线或分水岭边界时。

我发现,与ASCII分水岭工具相比,我的简单代码(对ASCII栅格执行此操作)提供了几乎相似的输出。有时边界上的几个像元之间存在差异,因此我确信ArcGIS遵循的是未经修改的D8算法。


谢谢您的阐述。但是使用 D8方向查找分水岭的算法是什么?请参阅dmahr的回答后的评论。
ub

嗨,谢谢,但这并不能真正回答问题。您用以下句子打它:“对于该单元,您将找到附近的所有对其有贡献的单元。对于这些相邻单元中的每一个,您将找到对其有贡献的单元,依此类推”。有许多不同的算法可以实现该搜索。问题是哪一个
詹姆斯(James)

4

之前曾有人问过这个问题,尽管可能情况略有不同。Spatial Analyst的水文工具集中的所有地理处理工具都使用D8流向模型,如“流向如何工作”页面中所述

有八个有效的输出方向与流可能进入的八个相邻单元有关。这种方法通常称为八向(D8)流动模型,并且遵循Jenson和Domingue(1988)中提出的方法。

詹森和多明格(Jenson and Domingue,1988)论文的副本可在此处获得

所有使用“流向”栅格作为输入的工具都可以通过关联使用此流向模型。这包括分水岭,流量累积,流量长度,填充等。


因此,我想接下来的问题是,该算法如何修改以返回集水区?
詹姆斯

分水岭工具从倾泻点向流向栅格导航。它与“流量累积”工具相反,只是它报告倾倒点的ID而不是描述栅格数量的输出栅格。
dmahr 2014年

1
好的,我想我需要更具体一些。我知道它做什么的概念。我不知道执行什么算法。也就是说,我认为这是某种搜索算法,但仍然可以。广度优先,深度优先,迭代加深深度优先等...
詹姆斯

1
谢谢dmahr。@whuber:据我所知,不同的搜索算法可能给出略有不同的结果?是的,找到通用算法不是问题,但是了解ESRI如何处理流域特定区域(例如DTM的平坦部分)很有用。
詹姆斯

1
詹姆斯(James)请编辑您的问题以澄清最后一点,以便该线程停止收集否则无用的“它是D8”答案。(什么对D8评论有帮助的是,如果你接受D8导致一个独特的流动方向图,然后有一个唯一正确的解决分水岭划分问题,因为流域是图本身的性质。因此,如果有任何模糊他们必须位于(A)的定义中的“分水岭,”(b)该D8方向如何计算,或(c)细胞如何水平(即,不具有独特D8方向)的处理)。
whuber

0

为了进一步思考这个问题,我在弧线中进行了分水岭分析:我采用了(填充的)DEM,计算了流向,并放置了一些与先前计算的流网络上的位置相对应的点。我运行了“分水岭”工具,它给了我一些不错的盆地,几乎覆盖了上游其余大部分区域(正如您所期望的那样):

分水岭形象

然后,我用Python编写了一种快速搜索算法(如上述答案),该算法检查流向网格并“遵循”流路。对于每个节点,我检查8个邻居,如果邻居流入当前节点,则以邻居节点作为输入递归调用相同的函数。

伪(ish)代码:

class d8():
    def __init__(self, arr):
       self.catchment = set()
       self.arr = arr

    def search(self, node):
        """ Searches all neighbouring nodes to find flow paths """ 

        # add the current node to the catchment
        self.catchment.add(node)

        # search the neighbours, ignore ones we already visited
        for each_neighbour:
            if neighbour is in self.catchment:
               do nothing

            # if the neighbour flows into the current node, visit that neighbour
            elif neighbour_flows_into_me:
               self.search(neighbour)

我使用相同的流向输入网格和相同的点之一来运行该函数。问题是,在该点上,arc返回的集水量约为40000个像元,而我的算法仅返回72个像元。

有人知道我在做什么错吗?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.