Ho una griglia binaria Arc / Info --- in particolare, un raster di accumulo del flusso ArcGIS --- e vorrei identificare tutte le celle con un valore specifico (o in un intervallo di valori). Alla fine, vorrei uno shapefile di punti che rappresentano queste celle.
Posso usare QGIS per aprire hdr.adf e ottenere questo risultato, il flusso di lavoro è:
- QGIS> Menu raster> Calcolatrice raster (contrassegnare tutti i punti con il valore target)
- QGIS> Menu raster> Poligonizza
- QGIS> Menu vettoriale> Sottomenu Geometria> Centroidi poligonali
- Modifica i centroidi per eliminare i poli centroidi indesiderati (quelli = 0)
Questo approccio "fa il lavoro", ma non mi piace perché crea 2 file che devo eliminare, quindi devo rimuovere i record indesiderati dal file di forma dei centroidi (cioè quelli = 0).
Una domanda esistente si avvicina a questo argomento, ma è su misura per ArcGIS / ArcPy e mi piacerebbe rimanere nello spazio FOSS.
Qualcuno ha una ricetta / script GDAL / Python esistente che interroga i valori della cella di un raster e quando viene trovato un valore target --- o un valore in un intervallo target ---, un record viene aggiunto a uno shapefile? Ciò non solo eviterebbe l'interazione dell'interfaccia utente, ma creerebbe un risultato pulito in un unico passaggio.
Ci ho provato lavorando contro una delle presentazioni di Chris Garrard , ma il lavoro raster non è nella mia timoniera e non voglio ingombrare la domanda con il mio codice debole.
Se qualcuno volesse il set di dati esatto con cui giocare, lo metto qui come .zip .
[Modifica note] Lasciandolo alle spalle per i posteri. Vedi gli scambi di commenti con om_henners. Fondamentalmente sono stati capovolti i valori x / y (riga / colonna). La risposta originale aveva questa linea:
(y_index, x_index) = np.nonzero(a == 1000)
invertito, in questo modo:
(x_index, y_index) = np.nonzero(a == 1000)
Quando ho riscontrato per la prima volta il problema illustrato nello screenshot, mi chiedevo se avevo implementato la geometria in modo errato e ho sperimentato capovolgendo i valori delle coordinate x / y in questa riga:
point.SetPoint(0, x, y)
..come..
point.SetPoint(0, y, x)
Tuttavia, ciò non ha funzionato. E non pensavo di provare a lanciare i valori nell'espressione Numpy di om_henners, credendo erroneamente che lanciarli su entrambe le righe fosse equivalente. Penso che il vero problema sia relativo ai valori x_size
e y_size
, rispettivamente 30
e -30
, che vengono applicati quando gli indici di riga e colonna vengono utilizzati per calcolare le coordinate dei punti per le celle.
[Modifica originale]
@om_henners, sto provando la tua soluzione, di concerto con un paio di destinatari per creare shapefile di punti usando ogr ( invisibleroads.com , Chris Garrard ), ma sto riscontrando un problema per cui i punti appaiono come se si riflettessero su una linea che passa attraverso 315/135 gradi.
Punti azzurri : creati dal mio approccio QGIS , sopra
Punti viola : creati dal codice py GDAL / OGR , di seguito
[Risolto]
Questo codice Python implementa la soluzione completa proposta da @om_henners. L'ho provato e funziona. Grazie uomo!
from osgeo import gdal
import numpy as np
import osgeo.ogr
import osgeo.osr
path = "D:/GIS/greeneCty/Greene_DEM/GreeneDEM30m/flowacc_gree/hdr.adf"
print "\nOpening: " + path + "\n"
r = gdal.Open(path)
band = r.GetRasterBand(1)
(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()
a = band.ReadAsArray().astype(np.float)
# This evaluation makes x/y arrays for all cell values in a range.
# I knew how many points I should get for ==1000 and wanted to test it.
(y_index, x_index) = np.nonzero((a > 999) & (a < 1001))
# This evaluation makes x/y arrays for all cells having the fixed value, 1000.
#(y_index, x_index) = np.nonzero(a == 1000)
# DEBUG: take a look at the arrays..
#print repr((y_index, x_index))
# Init the shapefile stuff..
srs = osgeo.osr.SpatialReference()
#srs.ImportFromProj4('+proj=utm +zone=15 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs')
srs.ImportFromWkt(r.GetProjection())
driver = osgeo.ogr.GetDriverByName('ESRI Shapefile')
shapeData = driver.CreateDataSource('D:/GIS/01_tutorials/flow_acc/ogr_pts.shp')
layer = shapeData.CreateLayer('ogr_pts', srs, osgeo.ogr.wkbPoint)
layerDefinition = layer.GetLayerDefn()
# Iterate over the Numpy points..
i = 0
for x_coord in x_index:
x = x_index[i] * x_size + upper_left_x + (x_size / 2) #add half the cell size
y = y_index[i] * y_size + upper_left_y + (y_size / 2) #to centre the point
# DEBUG: take a look at the coords..
#print "Coords: " + str(x) + ", " + str(y)
point = osgeo.ogr.Geometry(osgeo.ogr.wkbPoint)
point.SetPoint(0, x, y)
feature = osgeo.ogr.Feature(layerDefinition)
feature.SetGeometry(point)
feature.SetFID(i)
layer.CreateFeature(feature)
i += 1
shapeData.Destroy()
print "done! " + str(i) + " points found!"
srs.ImportFromWkt(r.GetProjection())
(anziché dover creare una proiezione da una stringa di proj nota).