Creare un raster in cui ogni cella registra la distanza dal mare?


10

Voglio creare un raster con una risoluzione di 25 metri × 25 metri, in cui ogni cella contiene la distanza dalla costa più vicina, calcolata dal centro della cella. Per fare questo, tutto ciò che ho è uno shapefile delle coste della Nuova Zelanda .

Ho provato a seguire il tutorial di Dominic Roye per averlo fatto in R che funziona ... in un certo senso. Va bene fino a circa 1 km × 1 km di risoluzione, ma se provo ad andare più in alto la RAM richiede ben più di quella disponibile sul mio PC (sono necessari ~ 70 gb di RAM) o qualsiasi altra a cui abbia accesso. Nel dire ciò, penso che questa sia una limitazione di R e sospetto che QGIS possa avere un modo più efficiente dal punto di vista computazionale di creare questo raster, ma sono nuovo e non riesco a capire come farlo.

Ho provato a seguire Creazione di raster con distanza dalla funzione utilizzando QGIS? per crearlo in QGIS ma restituisce questo errore:

_core.QgsProcessingException: impossibile caricare il layer sorgente per INPUT: C: /..../ Coastline / nz-coastlines-and-islands-polygons-topo-150k.shp non trovato

e non sono sicuro del perché.

Qualcuno ha qualche suggerimento su cosa potrebbe andare storto o un modo alternativo per farlo?

Modificare:

Il raster che spero di produrre avrebbe circa 59684 righe e 40827 colonne in modo che si sovrapponga al raster annuale del deficit idrico di LINZ. Se il raster che viene prodotto è più grande del raster annuale del deficit idrico, posso tagliare in R però ...

Una cosa che penso potrebbe essere un potenziale problema è che lo shapefile della costa della Nuova Zelanda ha una grande quantità di mare tra le isole e non sono interessato a calcolare la distanza dalla costa per queste celle. Voglio davvero solo calcolare i valori per le celle che includono una porzione di terra. Non sono sicuro di come fare questo, o se si tratta effettivamente di un problema.


1
Stai eseguendo uno script per farlo? O stai usando gli strumenti in QGIS? Qualcosa da controllare, anche se sembra che dovrebbe - controlla che il file esista effettivamente dove dici che lo fa ... controlla anche di avere accesso in lettura e scrittura a quella particolare cartella.
Keagan Allan,

Attualmente sto usando gli strumenti, ma sono abbastanza entusiasta di imparare la sceneggiatura, ma non sono sicuro da dove cominciare. Sono sicuro che il file esiste, poiché ho caricato il file .shp in QGIS e viene visualizzato come immagine. Dovrei avere anche l'accesso in lettura / scrittura poiché sono un amministratore sulla macchina ed è solo nel mio dropbox.
André.B,

Prova a spostarlo da Dropbox su un'unità locale. Potrebbe esserci un problema con il percorso che causa il rifiuto di QGIS. Quello che stai cercando di fare dovrebbe essere abbastanza semplice in QGIS. Quale versione di QGIS stai usando?
Keagan Allan,

1
Ok, prova a convertire la polilinea in un raster. Lo strumento di prossimità in QGIS richiede un input raster. Gioca con le impostazioni come da aiuto dello strumento: docs.qgis.org/2.8/en/docs/user_manual/processing_algs/gdalogr/… . Prendi nota, è ancora un processo intensivo, lo sto testando per divertimento ora e funziona da 30 minuti e continua ...
Keagan Allan,

1
Che dimensione del raster di output in termini di righe e colonne stai cercando di creare? Sarai davvero in grado di lavorare con quel raster dopo averlo creato? Se la dimensione del file dell'intera faccenda è un problema, potresti creare tessere più piccole, cosa che puoi anche fare in parallelo su un cluster o cloud per la velocità.
Spacedman,

Risposte:


9

Con PyQGIS e la libreria python GDAL non è molto difficile farlo. Sono necessari i parametri di trasformazione geografica (in alto a sinistra, la risoluzione di pixel x, la rotazione, in alto a sinistra y, la rotazione, la risoluzione di pixel ns) e il numero di righe e colonne per creare il raster risultante. Per calcolare la distanza dalla costa più vicina, è necessario un livello vettoriale per rappresentare la costa.

Con PyQGIS , ogni punto raster come centro della cella viene calcolato e la sua distanza dalla linea costiera viene misurata utilizzando il metodo "più vicinoSegmentoCon più" dalla classe QgsGeometry . La libreria python GDAL viene utilizzata per produrre un raster con questi valori di distanza nell'array di righe x colonne.

Il codice seguente è stato usato per creare un raster di distanza (risoluzione 25 m × 25 m e 1000 righe x 1000 colonne) a partire dal punto (397106.7689872353, 4499634.06675821); vicino alla costa occidentale degli Stati Uniti.

from osgeo import gdal, osr
import numpy as np
from math import sqrt

registry = QgsProject.instance()

line = registry.mapLayersByName('shoreline_10N')

crs = line[0].crs()

wkt = crs.toWkt()

feats_line = [ feat for feat in line[0].getFeatures()]

pt = QgsPoint(397106.7689872353, 4499634.06675821)

xSize = 25
ySize = 25

rows = 1000
cols = 1000

raster = [ [] for i in range(cols) ]

x =   xSize/2
y = - ySize/2

for i in range(rows):
    for j in range(cols):
        point = QgsPointXY(pt.x() + x, pt.y() + y)
        tupla = feats_line[0].geometry().closestSegmentWithContext(point)
        raster[i].append(sqrt(tupla[0]))

        x += xSize
    x =  xSize/2
    y -= ySize

data = np.array(raster)

# Create gtif file 
driver = gdal.GetDriverByName("GTiff")

output_file = "/home/zeito/pyqgis_data/distance_raster.tif"

dst_ds = driver.Create(output_file, 
                       cols, 
                       rows, 
                       1, 
                       gdal.GDT_Float32)

#writting output raster
dst_ds.GetRasterBand(1).WriteArray( data )

transform = (pt.x(), xSize, 0, pt.y(), 0, -ySize)

#setting extension of output raster
# top left x, w-e pixel resolution, rotation, top left y, rotation, n-s pixel resolution
dst_ds.SetGeoTransform(transform)

# setting spatial reference of output raster 
srs = osr.SpatialReference()
srs.ImportFromWkt(wkt)
dst_ds.SetProjection( srs.ExportToWkt() )

dst_ds = None

Dopo aver eseguito il codice sopra, il raster risultante è stato caricato in QGIS e appare come nell'immagine seguente (pseudocolor con 5 classi e rampa spettrale). La proiezione è UTM 10 N (EPSG: 32610)

inserisci qui la descrizione dell'immagine


Questo potrebbe non essere un problema, ma una cosa di cui sono un po 'preoccupato è che il poligono è della Nuova Zelanda e delle isole circostanti, il che significa che include un'enorme quantità di mare circostante. Sto cercando di aggirare il codice, ma con il tuo esempio sarei in grado di impostare il valore di tutte le celle in mare su NA? Sono davvero interessato solo alla distanza dal mare dai punti sulla terra.
André.B,

Ci scusiamo in anticipo se questa è una domanda stupida, ma come faccio a scegliere un nuovo punto di partenza in Nuova Zelanda nel modo in cui hai impostato le coordinate per gli stati? Inoltre, come posso mantenerlo in EPSG: 2193?
André.B,

7

Potrebbe essere una soluzione da provare:

  1. Genera una griglia (digitare "punto", algoritmo "Crea griglia")
  2. Calcola la distanza più vicina tra i tuoi punti (griglia) e la tua linea (costa) con l'algoritmo "Unisci attributo per più vicino". Fai attenzione a scegliere solo un massimo di 1 vicini più vicini.

Ora dovresti avere un nuovo livello punti con la distanza dalla costa come in questo esempio inserisci qui la descrizione dell'immagine

  1. Se necessario, puoi convertire il tuo nuovo layer di punti in un raster (algoritmo "rasterizza")

inserisci qui la descrizione dell'immagine


2

All'interno di QGIS è possibile provare il plug-in GRASS. Per quanto ne so, gestisce la memoria meglio di R, e mi aspetto che l'altra soluzione fallisca su aree estese.

il comando GRASS si chiama r.grow.distance, che puoi trovare nella barra degli strumenti di elaborazione. Nota che all'inizio devi convertire la tua linea in raster.

inserisci qui la descrizione dell'immagine

Uno dei tuoi problemi potrebbe essere la dimensione dell'output, quindi puoi aggiungere alcune utili opzioni di creazione come (per un file tif) BIGTIFF = YES, TILED = YES, COMPRESS = LZW, PREDICTOR = 3


Esiste un modo per eliminare qualsiasi area marina in modo da ridurre le dimensioni / i tempi di calcolo?
André.B,

in teoria, se si utilizza la distanza dalla vista (tutti vedono pixel con lo stesso valore, ovvero un poligono) anziché dalla linea di costa, è necessario risparmiare tempo di calcolo. Le dimensioni non compresse del raster dovrebbero essere le stesse, ma la compressione sarà più efficiente, quindi è necessario ridurre anche le dimensioni finali.
Radouxju,

0

Vorrei provare diversamente. Se stai usando il poligono della Nuova Zelanda, converti i bordi poligonali in linea. Dopodiché crea un buffer sul confine per ogni 25 metri di distanza dal confine (forse il centoride potrebbe aiutare a determinare quando fermarsi). Quindi tagliare i buffer con il poligono e quindi convertire i poligoni in raster. Non sono sicuro che funzionerebbe, ma sicuramente avrai bisogno di meno RAM. E PostGiS è eccezionale in caso di problemi di prestazioni.

Spero che possa aiutare almeno un po ':)


0

Inizialmente non avevo intenzione di rispondere alla mia domanda, ma un mio collega (che non utilizza questo sito), mi ha scritto un sacco di codice Python per fare quello che sto cercando; inclusa la limitazione delle cellule per avere la distanza dalla costa solo per le cellule terrestri e lasciare le cellule a base di mare come NA. Il seguente codice dovrebbe essere in grado di funzionare da qualsiasi console Python, con le uniche cose che necessitano di essere alterate:

1) Inserire il file di script nella stessa cartella del file di forma di interesse;

2) cambia il nome del file di forma nello script Python in qualunque sia il nome del tuo file di forma;

3) impostare la risoluzione desiderata, e;

4) modificare l'estensione per abbinare altri raster.

Gli shapefile più grandi di quelli che sto usando richiederanno grandi quantità di RAM, ma per il resto lo script è veloce da eseguire (circa tre minuti per produrre un raster con risoluzione di 50m e dieci minuti per un raster con risoluzione di 25m).

#------------------------------------------------------------------------------

from osgeo import gdal, ogr
import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
import time

startTime = time.perf_counter()

#------------------------------------------------------------------------------

# Define spatial footprint for new raster
cellSize = 50 # ANDRE CHANGE THIS!!
noData = -9999
xMin, xMax, yMin, yMax = [1089000, 2092000, 4747000, 6224000]
nCol = int((xMax - xMin) / cellSize)
nRow = int((yMax - yMin) / cellSize)
gdal.AllRegister()
rasterDriver = gdal.GetDriverByName('GTiff')
NZTM = 'PROJCS["NZGD2000 / New Zealand Transverse Mercator 2000",GEOGCS["NZGD2000",DATUM["New_Zealand_Geodetic_Datum_2000",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6167"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4167"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",173],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",1600000],PARAMETER["false_northing",10000000],AUTHORITY["EPSG","2193"],AXIS["Easting",EAST],AXIS["Northing",NORTH]]'

#------------------------------------------------------------------------------ 

inFile = "new_zealand.shp" # CHANGE THIS!!

# Import vector file and extract information
vectorData = ogr.Open(inFile)
vectorLayer = vectorData.GetLayer()
vectorSRS = vectorLayer.GetSpatialRef()
x_min, x_max, y_min, y_max = vectorLayer.GetExtent()

# Create raster file and write information
rasterFile = 'nz.tif'
rasterData = rasterDriver.Create(rasterFile, nCol, nRow, 1, gdal.GDT_Int32, options=['COMPRESS=LZW'])
rasterData.SetGeoTransform((xMin, cellSize, 0, yMax, 0, -cellSize))
rasterData.SetProjection(vectorSRS.ExportToWkt())
band = rasterData.GetRasterBand(1)
band.WriteArray(np.zeros((nRow, nCol)))
band.SetNoDataValue(noData)
gdal.RasterizeLayer(rasterData, [1], vectorLayer, burn_values=[1])
array = band.ReadAsArray()
del(rasterData)

#------------------------------------------------------------------------------

distance = ndimage.distance_transform_edt(array)
distance = distance * cellSize
np.place(distance, array==0, noData)

# Create raster file and write information
rasterFile = 'nz-coast-distance.tif'
rasterData = rasterDriver.Create(rasterFile, nCol, nRow, 1, gdal.GDT_Float32, options=['COMPRESS=LZW'])
rasterData.SetGeoTransform((xMin, cellSize, 0, yMax, 0, -cellSize))
rasterData.SetProjection(vectorSRS.ExportToWkt())
band = rasterData.GetRasterBand(1)
band.WriteArray(distance)
band.SetNoDataValue(noData)
del(rasterData)

#------------------------------------------------------------------------------

endTime = time.perf_counter()

processTime = endTime - startTime

print(processTime)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.