GDAL - Führen Sie eine einfache Analyse der Pfade mit den geringsten Kosten durch

8

Ich untersuche Methoden, um mit gdal eine einfache Pfadanalyse mit den geringsten Kosten durchzuführen. Mit einfach meine ich die Verwendung der Steigung eines Dem als einzigen Kostenfaktor.

Ich würde es vorziehen, die Python- oder .net-Bindungen zu verwenden, werde aber alles nehmen. Kann jemand gute Tutorials oder ähnliches vorschlagen?

user890
quelle
3
Verwenden Sie für analytische Fragen möglicherweise besser ein GIS als eine Abstraktionsbibliothek für Datenformate ...
markusN
2
Was ist aus Neugier die Anwendung? Es ist schwer vorstellbar, für was die Steigung des DEM ein realistischer Indikator für die Reisekosten wäre. Sind Sie sicher, dass Sie das brauchen? Es wäre schade, wenn Sie nach dem Schreiben dieses Codes feststellen würden, dass er Ihr Problem nicht wirklich gelöst hat!
whuber
Steigung kann als Reisekosten nützlich sein, wenn Sie ein schwerkraftabhängiges Ausbreitungsmodell modellieren, obwohl ich auch einige andere Faktoren erwarten würde, anstatt nur Steigung.
MappaGnosis
Außerdem zeigt die Steigung normalerweise die maximale Steigung in jeder Zelle, selbst wenn die Route nicht direkt bergab oder bergauf verläuft.
Matthew Snape

Antworten:

8

Das folgende Skript führt eine Pfadanalyse mit den geringsten Kosten durch. Eingabeparameter sind ein Kostenoberflächenraster (z. B. Steigung) sowie Start- und Stoppkoordinaten. Ein Raster mit dem erstellten Pfad wird zurückgegeben. Es erfordert die Skimage-Bibliothek und GDAL.

Beispielsweise wird der kostengünstigste Pfad zwischen Punkt 1 und Punkt 2 basierend auf einem Steigungsraster erstellt: Geben Sie hier die Bildbeschreibung ein

import gdal, osr
from skimage.graph import route_through_array
import numpy as np


def raster2array(rasterfn):
    raster = gdal.Open(rasterfn)
    band = raster.GetRasterBand(1)
    array = band.ReadAsArray()
    return array  

def coord2pixelOffset(rasterfn,x,y):
    raster = gdal.Open(rasterfn)
    geotransform = raster.GetGeoTransform()
    originX = geotransform[0]
    originY = geotransform[3] 
    pixelWidth = geotransform[1] 
    pixelHeight = geotransform[5]
    xOffset = int((x - originX)/pixelWidth)
    yOffset = int((y - originY)/pixelHeight)
    return xOffset,yOffset

def createPath(CostSurfacefn,costSurfaceArray,startCoord,stopCoord):   

    # coordinates to array index
    startCoordX = startCoord[0]
    startCoordY = startCoord[1]
    startIndexX,startIndexY = coord2pixelOffset(CostSurfacefn,startCoordX,startCoordY)

    stopCoordX = stopCoord[0]
    stopCoordY = stopCoord[1]
    stopIndexX,stopIndexY = coord2pixelOffset(CostSurfacefn,stopCoordX,stopCoordY)

    # create path
    indices, weight = route_through_array(costSurfaceArray, (startIndexY,startIndexX), (stopIndexY,stopIndexX),geometric=True,fully_connected=True)
    indices = np.array(indices).T
    path = np.zeros_like(costSurfaceArray)
    path[indices[0], indices[1]] = 1
    return path

def array2raster(newRasterfn,rasterfn,array):
    raster = gdal.Open(rasterfn)
    geotransform = raster.GetGeoTransform()
    originX = geotransform[0]
    originY = geotransform[3] 
    pixelWidth = geotransform[1] 
    pixelHeight = geotransform[5]
    cols = array.shape[1]
    rows = array.shape[0]

    driver = gdal.GetDriverByName('GTiff')
    outRaster = driver.Create(newRasterfn, cols, rows, gdal.GDT_Byte)
    outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
    outband = outRaster.GetRasterBand(1)
    outband.WriteArray(array)
    outRasterSRS = osr.SpatialReference()
    outRasterSRS.ImportFromWkt(raster.GetProjectionRef())
    outRaster.SetProjection(outRasterSRS.ExportToWkt())
    outband.FlushCache()    

def main(CostSurfacefn,outputPathfn,startCoord,stopCoord):

    costSurfaceArray = raster2array(CostSurfacefn) # creates array from cost surface raster

    pathArray = createPath(CostSurfacefn,costSurfaceArray,startCoord,stopCoord) # creates path array

    array2raster(outputPathfn,CostSurfacefn,pathArray) # converts path array to raster


if __name__ == "__main__":
    CostSurfacefn = 'CostSurface.tif'
    startCoord = (345387.871,1267855.277)
    stopCoord = (345479.425,1267799.626)
    outputPathfn = 'Path.tif'
    main(CostSurfacefn,outputPathfn,startCoord,stopCoord)
ustroetz
quelle
Ich mag deine Antwort. Wie gehen Sie zB mit Seen um, bei denen der Kostenwert für ein größeres Gebiet gleich ist? Mein Weg führt durch einen See und schlängelt sich wie eine Schlange herum, bis das Gebiet bedeckt ist, bevor es wie erwartet weitergeht? Vielen Dank.
Michael
Daran habe ich lange nicht mehr gearbeitet. Sie haben wahrscheinlich schon daran gedacht, aber ich würde die Kosten für den See einfach sehr hoch setzen. Auf diese Weise sollte der Weg den See meiden, nicht wahr?
Ustroetz
Ja, ich habe den See auf etwas mehr als 0 eingestellt, auf diese Weise entstehen Kosten und das Mäandern verschwindet.
Michael
3

Sie können den A * -Suchalgorithmus verwenden, indem Sie die Steigung als Kosten zwischen den generierten Knoten verwenden. So sehen Sie schnell, wie das aussieht:

Ein Stern animiert

Siehe A * Suchalgorithmus (Wiki) und Python A * Suchalgorithmus (SO)

A * verstehen.

Für eine Pistenkarte gibt es da draußen Optionen - hier ist eine.

Mit einer Steigungskarte (Raster) können Sie mit GDAL Kostenwerte daraus abrufen.

BuckFilledPlatypus
quelle
2
Können Sie erklären, wie Sie das Steigungsraster zu einem Diagramm machen, damit es in dem von Ihnen genannten Python A * -Suchalgorithmuscode verwendet werden kann? Ich weiß, wie ich mit GDAL den Wert aus dem Raster herausholen kann. aber wie soll ich es speichern, um es als Grafik zu verwenden (zB Wörterbuch?)?
Ustroetz