Welcher Algorithmus wird vom ArcGIS Watershed-Tool verwendet?

10

Weiß jemand, welche Art von Algorithmus im ArcGIS Watershed-Tool (im Spatial Analyst-Paket) verwendet wird?

Sehr wenig Informationen auf Esris Website ... aber ich vermute, dass es sich um eine Art Tiefen- / Breitensuche handelt.

Ich habe mir diese ArcGIS Online-Hilfeseiten angesehen:

Ja, es wird das Raster für die Flussrichtung verwendet, aber mit welchem ​​Algorithmus wird das Raster durchlaufen?

Bitte beachten Sie, dass ich nicht nach Antworten im Sinne von "Es verwendet D8 ..." suche. D8 ist nicht wirklich ein Algorithmus, sondern ein Modell zur Definition des Algorithmus, den Sie verwenden würden. IE Sie könnten das D8-Schema in einem Tiefensuchalgorithmus und / oder einem Breitensuchalgorithmus implementieren

James
quelle
James, ich versuche das Gleiche zu tun, dh eine App zu erstellen, die eine bestimmte Koordinate verwendet und uns eine Abgrenzung der Wasserscheide gibt. Ich benutze Python. Sprechen wir über unsere Fortschritte.
Ich benutze auch Python. Ich beginne mit dem einfacheren Problem, ein Strömungsrichtungsgitter zu berechnen und von dort fortzufahren.
James

Antworten:

6

Die Methode, die ich in einigen Sprachen implementiert habe und die von ESRI verwendet wird (leider keine anderen Referenzen als Jenson und Domingue, die an anderer Stelle auf dieser Seite zitiert werden), besteht darin, an einer vom Benutzer bereitgestellten "Pour-Point" -Zelle oder einer Zelle zu beginnen Untersuchen Sie am Rand des Strömungsrichtungsgitters (fdr) seine acht Nachbarn, um herauszufinden, welche von diesen direkt in die aktuelle Zelle fließen, und ordnen Sie diese Zellen der aktuellen "Wasserscheide" im Ausgangsgitter zu. Dann ruft sich die Funktion rekursiv einmal für jeden der einströmenden Nachbarn auf. Dieser Vorgang wird wiederholt, bis alle einströmenden Zellen für einen Stockpunkt erschöpft sind, und wird dann für alle Stockpunkte wiederholt.

Das Design des rekursiven Algorithmus kann ziemlich teuer sein, da es möglicherweise versucht, viele Daten im Speicher zu halten, die Seite auf die Festplatte austauschen muss und daher im Allgemeinen unter I / O-Verlangsamungen leidet.

(Siehe Whubers Kommentar unten zu verschiedenen Rekursionsmethoden, wenn Sie RYO wollen.)

_____________ BEARBEITEN _____________

Als Beispiel habe ich meinen alten C-Code ausgegraben (Hinweis: Obwohl die meisten Python-Spieler möglicherweise aus dem Raum rennen möchten, sollte dies nicht schlecht sein). Ich dachte, es könnte interessant sein, dies zu veranschaulichen. Obwohl ich erst jetzt oberflächlich mit der Rekursion "Breite zuerst" und "Tiefe zuerst" vertraut bin, denke ich, dass meine Routine tatsächlich Tiefe zuerst ist (und dass meine obige Beschreibung der natürlichen Sprache irreführend war), basierend auf diesem Stackoverflow-Posting (hoffentlich @ whuber oder eine andere Person, die klüger als ich ist, kann dies bestätigen / ablehnen).

Code: Erklärung: idirist das Raster der Durchflussrichtungswerte. offsetbezieht sich auf die zentrale Zelle, die gerade analysiert wird, und offüberprüft jeden Nachbarn dieser Zelle. Dies ruft eine andere Funktion auf, does_it_flow_into_medie einen Booleschen Wert zurückgibt, um festzustellen, ob das Flussverzeichnis der benachbarten Zelle auf die aktuelle Zelle zeigt. Wenn dies für einen Nachbarn zutrifft, kehren Sie zu diesem Ort zurück.

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 */
}
Roland
quelle
Sie beschreiben die Rekursion mit der Breite zuerst. Mithilfe eines kleinen Stapels können Sie eine effiziente Tiefenrekursion implementieren, die wenig Speicher benötigt. Das Hauptleistungsproblem würde große Wassereinzugsgebiete betreffen, in denen Kacheln des Gitters möglicherweise wiederholt in den Arbeitsspeicher und aus dem Arbeitsspeicher heraus ausgetauscht werden müssen. Wie in Kommentaren zu anderen Antworten erörtert, besteht das eigentliche Problem jedoch in der Bewältigung von Zellen, in denen es keine eindeutig bestimmte D8-Richtung gibt, insbesondere von Zellen, die in ausgedehnten flachen horizontalen Flecken liegen (wie sie beispielsweise durch vorläufige Routinen zum Befüllen von Senken erzeugt wurden).
whuber
Auf jeden Fall ein Müll-in-Müll-Out-Problem. Was ich und die meisten GIss tun, wird die Eingabe nicht bereinigen! Klingt so, als müsste ich die Tiefenrekursion nachschlagen, um meinen Hack zu polieren.
Roland
Ich denke nicht, dass dies Müll ist - denken Sie daran, unabhängig davon, wie die Implementierung aufgeschlüsselt ist, ist die ursprüngliche Eingabe das DEM selbst und nicht die D8-Codierung von jemandem - aber es ist definitiv eine Herausforderung. In der realen Welt gibt es viele Orte, die so flach sind, dass die Strömungsrichtung schwer zu bestimmen ist: Jeder statische Wasserkörper ist ein gutes Beispiel. In der Tat müssen Sie Auslässe von Seen und anderen flachen Bereichen finden und Sie müssen mit flachen Bereichen mit mehreren Auslässen fertig werden. Dies erfordert nicht-lokale Suchvorgänge, die schwierig durchzuführen sind.
whuber
Ich bin dann wahrscheinlich verwirrt. Ich denke, wir diskutieren help.arcgis.com/de/arcgisdesktop/10.0/help../index.html#//… , das flowdir als Eingabe verwendet. Ich will uns nicht ins Unkraut ziehen, wenn ich den Rest nicht genau genug gelesen habe!
Roland
Nein, ich denke, Sie haben Recht: Wenn ich die Frage erneut lese, sehe ich, dass sie sich speziell auf die Verarbeitung des Rasters für die Flussrichtung als Eingabe konzentriert und nicht auf die allgemeinere Situation, die ich mir vorgestellt habe. Also +1 auf Ihre Antwort, um sie direkt und mit Einsicht und hilfreichen Hinweisen anzusprechen.
whuber
4

In der ArcGIS-Hilfe heißt es:

Wassereinzugsgebiete können aus einem DEM abgegrenzt werden, indem die Flussrichtung berechnet und im Werkzeug Wassereinzugsgebiet verwendet wird. Um den beitragenden Bereich zu bestimmen, muss zuerst mit dem Werkzeug Flussrichtung ein Raster erstellt werden, das die Flussrichtung darstellt.

Die Strömungsrichtung wird aus dem DEM unter Verwendung der D8-Methode berechnet . Dabei wird die Strömung abstrahiert, indem für jede Zelle berechnet wird, zu welchem ​​ihrer 8 Nachbarn das Wasser aus dieser Zelle fließt.

Es gibt viele Alternativen zu D8, wie Rho8, Froh8 und Stream Tubes, aber die meisten GIS-Programme, einschließlich ArcGIS, verwenden D8, da es einfacher und weniger rechenintensiv ist als andere.


Vor einigen Jahren arbeitete ich an einem Watershed Delineation-Projekt, und wir hatten aufgrund von ArcGIS mit der D8-Methode mehrere Probleme. Die beiden Hauptprobleme waren

  • D8 erlaubt nur Uni Directional Flow. Wasser kann aus einer Zelle nur in eine Richtung abfließen.
  • Die erzeugten Stromflüsse hatten eine große Vorspannung entlang der diagonalen Achse. Dies führte zu seltsam aussehenden Strömen.

Aus unseren Daten wussten wir, dass diese beiden Probleme große Probleme waren, daher hatte ich einige Tools entwickelt, um Strömungsrichtungen mit Hybridmethoden zu generieren.

Eine meiner frühesten Aufgaben war das Reverse Engineering des Einzugsgebietsberechnungstools. Ich fand, dass es logisch ziemlich einfach war. Wenn Sie das Einzugsgebiet für einen bestimmten Punkt (auch als Stockpunkt bezeichnet) suchen möchten, finden Sie zuerst die Zelle, zu der es gehört. Oft werden Sie versuchen, es an den Punkt mit der höchsten Durchflussakkumulation in einer bestimmten Toleranz zu bringen.

Für diese Zelle finden Sie alle Zellen in der Nachbarschaft, die dazu beitragen. Für jede dieser Nachbarschaftszellen finden Sie die Zellen, die zu ihnen beitragen, und so weiter. Sie setzen diesen iterativen Prozess fort, bis Sie keine neuen Zellen mehr finden. Dann haben Sie die Gratlinien oder die Wasserscheidegrenze erreicht.

Ich stellte fest, dass mein einfacher Code, der dies für ASCII-Raster ausführte, im Vergleich zum Watershed-Tool von ArcGIS eine fast ähnliche Ausgabe lieferte. Manchmal gab es einen Unterschied zwischen einigen Zellen an der Grenze, daher bin ich überzeugt, dass ArcGIS einem unveränderten D8-Algorithmus folgt.

Devdatta Tengshe
quelle
Vielen Dank für die Ausarbeitung. Aber wie lautet der Algorithmus für die Verwendung der D8-Anweisungen zum Auffinden von Wassereinzugsgebieten? Bitte beachten Sie die Kommentare nach der Antwort von dmahr .
whuber
Hallo, danke, aber das beantwortet die Frage nicht wirklich. Sie treffen darauf mit dem Satz "Für diese Zelle finden Sie alle Zellen in der Nachbarschaft, die dazu beitragen. Für jede dieser Nachbarschaftszellen finden Sie die Zellen, die zu ihnen beitragen und so weiter". Es gibt viele verschiedene Algorithmen, um diese Suche zu implementieren. Die Frage ist welche
James
4

Dies wurde schon früher gefragt , wenn auch vielleicht in einem etwas anderen Kontext. Alle Geoverarbeitungswerkzeuge im hydrologischen Toolset von Spatial Analyst verwenden das D8-Flussrichtungsmodell , wie auf der Seite Funktionsweise der Flussrichtung angegeben :

Es gibt acht gültige Ausgangsrichtungen, die sich auf die acht benachbarten Zellen beziehen, in die der Fluss fließen könnte. Dieser Ansatz wird allgemein als Strömungsmodell mit acht Richtungen (D8) bezeichnet und folgt einem in Jenson und Domingue (1988) vorgestellten Ansatz.

Eine Kopie des Papiers von Jenson und Domingue (1988) finden Sie hier .

Alle Werkzeuge, die Flow Direction-Raster als Eingabe verwenden, verwenden dieses Flow Direction-Modell durch Zuordnung. Dies umfasst Wasserscheide, Durchflussakkumulation, Durchflusslänge, Füllung usw.

dmahr
quelle
Ich nehme an, eine Folgefrage wäre, wie dieser Algorithmus geändert wird, um das Einzugsgebiet zurückzugeben.
James
Das Watershed-Werkzeug navigiert von den Stockpunkten aus durch das Raster für die Flussrichtung. Dies ist die Umkehrung des Flow Accumulation-Tools, mit der Ausnahme, dass anstelle des Ausgabe-Rasters, das die Anzahl der Zellen beschreibt, die ID des Stockpunkts angegeben wird.
dmahr
1
Ok, ich denke ich muss ein bisschen genauer sein. Ich kenne das Konzept dessen, was es tut. Ich weiß nicht, welcher Algorithmus implementiert ist. Das heißt, ich nehme an, es ist eine Art Suchalgorithmus, aber es könnte immer noch sein; Breite zuerst, Tiefe zuerst, iterative Vertiefung Tiefe zuerst usw.
James
1
danke dmahr. @whuber: Soweit ich weiß, können verschiedene Suchalgorithmen leicht unterschiedliche Ergebnisse liefern? Und ja, es ist kein Problem, einen generischen Algorithmus zu finden, aber es ist nützlich zu lernen, wie ESRI mit wassereinzugsgebietsspezifischen Bereichen (z. B. flachen Teilen eines DTM) umgeht.
James
1
James Bitte bearbeiten Sie Ihre Frage, um diesen letzten Punkt zu klären, damit dieser Thread keine ansonsten nutzlosen "Es ist D8" -Antworten mehr sammelt. (Was ist hilfreich über die D8 Kommentare ist , dass , wenn Sie annehmen , dass D8 führt zu einer einzigartigen Strömungsrichtung Graph, dann gibt es eine einzigartige richtige Lösung für das Einzugsgebiet Abgrenzung Problem, weil die Wasserscheiden sind Eigenschaften des Graphen selbst. So , wenn es Alle Unklarheiten, in denen sie liegen müssen, sind (a) die Definition von "Wasserscheide", (b) wie die D8-Richtungen berechnet werden oder (c) wie horizontale Zellen (dh ohne eine eindeutige D8-Richtung) behandelt werden.)
whuber
0

Um diese Frage genauer zu untersuchen, führte ich eine Wassereinzugsgebietsanalyse im Bogen durch: Ich nahm ein (gefülltes) DEM, berechnete die Strömungsrichtung und platzierte einige Punkte, die Positionen in einem zuvor berechneten Stromnetz entsprachen. Ich habe das Tool "Wasserscheide" ausgeführt und es hat mir ein paar schöne Becken gegeben, die den größten Teil des verbleibenden Bereichs "stromaufwärts" abdecken (wie zu erwarten):

Wasserscheide Bild

Ich habe dann einen Schnellsuchalgorithmus in Python codiert (wie die obige Antwort), der das Flussrichtungsgitter überprüft und den Flusspfaden "folgt". Für jeden Knoten überprüfe ich die 8 Nachbarn und wenn ein Nachbar in den aktuellen Knoten fließt, rufe ich dieselbe Funktion rekursiv mit dem Nachbarknoten als Eingabe auf.

Pseudo (ish) Code:

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)

Ich habe diese Funktion mit demselben Eingangsraster für die Flussrichtung und einem der gleichen Punkte ausgeführt. Das Problem ist, dass mein Algorithmus nur 72 Zellen zurückgibt, wenn arc für diesen Punkt ein Einzugsgebiet von etwa 40000 Zellen zurückgibt.

Weiß jemand was ich falsch mache?

James
quelle