GDAL - Executar análise simples de caminhos de menor custo

8

Estou investigando métodos para executar uma análise simples de caminho de menor custo com o gdal. Simplesmente, quero dizer usando a inclinação de um dem como o único fator de custo.

Eu preferiria usar as ligações python ou .net, mas levará qualquer coisa. Alguém pode sugerir bons tutoriais ou algo parecido?

user890
fonte
3
Por questões analíticas, talvez melhor usar um GIS ao invés de uma biblioteca de abstração formato de dados ...
markusN
2
Por curiosidade, qual é a aplicação? É difícil pensar em algo para o qual a inclinação do DEM seria uma proxy realista do custo da viagem. Tem certeza de que é disso que precisa? Seria uma pena se, depois de se esforçar para escrever este código, você descobrisse que ele realmente não resolveu o seu problema!
whuber
A inclinação pode ser útil como custo de viagem se você estiver modelando algum tipo de modelo de dispersão dependente da gravidade, embora eu esperasse outros fatores também, em vez de apenas a inclinação.
MappaGnosis
Além disso, a inclinação geralmente mostra a inclinação máxima em cada célula, mesmo se a rota não estiver viajando diretamente para baixo ou para cima.
Matthew Snape

Respostas:

8

O script a seguir executa uma análise de caminho de menor custo. Os parâmetros de entrada são uma varredura de superfície de custo (por exemplo, inclinação) e coordenadas de partida e parada. Uma varredura com o caminho criado é retornada. Requer a biblioteca skimage e o GDAL.

Por exemplo, o caminho de menor custo entre o ponto 1 e o ponto 2 é criado com base em uma varredura de inclinação: insira a descrição da imagem aqui

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
fonte
Eu gosto da sua resposta. Como você lida com, por exemplo, lagos onde o valor do custo é o mesmo para uma área maior. Meu caminho atravessa um lago e meio que serpenteia como uma cobra até que a área seja coberta antes de continuar como esperado? Obrigado.
Michael
Não trabalho nisso há muito tempo. Você provavelmente já pensou nisso, mas eu definiria o custo do lago realmente alto. Desta forma, o caminho deve evitar o lago, não deveria?
ustroetz
Sim, eu defino o lago para ficar um pouco acima de 0, dessa forma há um custo e os meandros desaparecem.
Michael
3

Você pode usar o algoritmo de pesquisa A * usando inclinação como o custo entre os nós gerados. Para ver uma visualização rápida de como isso é:

Uma estrela animada

Consulte A * Search Algorithm (Wiki) e Python A * Search Algorithm (SO)

entender A *.

Para um mapa de inclinação, existem opções por aí - Aqui está uma.

Com um mapa de inclinação (raster), você pode obter valores de custo com o GDAL.

BuckFilledPlatypus
fonte
2
Você pode explicar como transformar a inclinação em um gráfico para que possa ser usada no código do algoritmo de pesquisa Python A * que você apontou? Eu sei como obter o valor da varredura com GDAL. mas como devo armazená-lo para usá-lo como um gráfico (por exemplo, dicionário?)?
ustroetz