GDAL: realice un análisis de ruta de menor costo simple

8

Estoy investigando métodos para realizar un análisis de ruta simple de menor costo con gdal. Por simple, me refiero a usar la pendiente de una dem como el único factor de costo.

Preferiría hacerlo usando los enlaces de python o .net, pero tomaré cualquier cosa. ¿Alguien puede sugerir buenos tutoriales o similares?

usuario890
fuente
3
Para preguntas analíticas, tal vez un mejor uso de un SIG en lugar de una biblioteca de abstracción de formato de datos ...
markusN
2
Por curiosidad, ¿cuál es la aplicación? Es difícil pensar en algo para lo que la pendiente del DEM sea un indicador realista del costo del viaje. ¿Estás seguro de que esto es lo que necesitas? ¡Sería una pena que, después de esforzarse por escribir este código, descubriera que en realidad no resolvió su problema!
whuber
La pendiente podría ser útil como costo de viaje si está modelando algún tipo de modelo de dispersión dependiente de la gravedad, aunque también esperaría algunos otros factores en lugar de solo la pendiente.
MappaGnosis el
Además, la pendiente generalmente muestra la pendiente máxima en cada celda, incluso si la ruta no viaja directamente cuesta abajo o cuesta arriba.
Matthew Snape

Respuestas:

8

El siguiente script realiza un análisis de ruta de menor costo. Los parámetros de entrada son un ráster de superficie de costo (por ejemplo, pendiente) y coordenadas de inicio y parada. Se devuelve un ráster con la ruta creada. Requiere la biblioteca de skimage y GDAL.

Por ejemplo, la ruta de menor costo entre el punto 1 y el punto 2 se crea en base a un ráster de pendiente: ingrese la descripción de la imagen aquí

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
fuente
Me gusta tu respuesta. ¿Cómo lidiar con, por ejemplo, lagos donde el valor del costo es el mismo para un área más grande? ¿Mi camino atraviesa un lago y deambula como una serpiente hasta que el área está cubierta antes de que continúe como se esperaba? Gracias.
Michael
No he trabajado en esto por mucho tiempo. Probablemente ya pensaste en esto, pero solo establecería el costo para el lago realmente alto. De esta manera, el camino debe evitar el lago, ¿no?
ustroetz
Sí, configuré el lago para que sea un poco más de 0, de esa manera hay un costo y el meandro desaparece.
Michael
3

Puede usar el algoritmo de búsqueda A * usando la pendiente como el costo entre los nodos generados. Para ver una visualización rápida de cómo se ve:

Una estrella animada

Consulte A * Algoritmo de búsqueda (Wiki) y Python A * Algoritmo de búsqueda (SO)

para entender A *.

Para un mapa de pendientes hay opciones disponibles: aquí hay una.

Con un mapa de pendientes (ráster) puede obtener valores de costos con GDAL.

BuckFilledPlatypus
fuente
2
¿Puede explicar cómo hacer que la pendiente sea ráster en un gráfico para que pueda usarse en el código de algoritmo de búsqueda Python A * que señaló? Sé cómo obtener el valor del ráster con GDAL. pero ¿qué debo guardar para usarlo como gráfico (por ejemplo, Diccionario?)?
ustroetz