Tengo un Arc / Info Binary Grid --- específicamente, un ráster de acumulación de flujo ArcGIS --- y me gustaría identificar todas las celdas que tienen un valor específico (o en un rango de valores). En última instancia, me gustaría un archivo de formas de puntos que representen estas celdas.
Puedo usar QGIS para abrir hdr.adf y obtener este resultado, el flujo de trabajo es:
- QGIS> Menú ráster> Calculadora ráster (marque todos los puntos con el valor objetivo)
- QGIS> Menú ráster> Poligonalizar
- QGIS> Menú de vectores> Submenú Geometría> Centroides poligonales
- Edite los centroides para eliminar los poli centroides no deseados (aquellos = 0)
Este enfoque "hace el trabajo", pero no me atrae porque crea 2 archivos que tengo que eliminar, luego tengo que eliminar los registros no deseados del archivo de forma de los centroides (es decir, aquellos = 0).
Una pregunta existente aborda este tema, pero está diseñada para ArcGIS / ArcPy, y me gustaría permanecer en el espacio FOSS.
¿Alguien tiene una receta / secuencia de comandos GDAL / Python existente que interrogue los valores de celda de un ráster, y cuando se encuentra un valor objetivo --- o un valor en un rango objetivo ---, se agrega un registro a un archivo de forma? Esto no solo evitaría la interacción de la interfaz de usuario, sino que crearía un resultado limpio en una sola pasada.
Intenté trabajar contra una de las presentaciones de Chris Garrard , pero el trabajo raster no está en mi timonera y no quiero saturar la pregunta con mi código débil.
Si alguien quiere jugar con el conjunto de datos exacto, lo pongo aquí como un .zip .
[Editar notas] Dejando esto atrás para la posteridad. Ver intercambios de comentarios con om_henners. Básicamente, los valores x / y (fila / columna) se voltearon. La respuesta original tenía esta línea:
(y_index, x_index) = np.nonzero(a == 1000)
invertido, así:
(x_index, y_index) = np.nonzero(a == 1000)
Cuando encontré por primera vez el problema ilustrado en la captura de pantalla, me pregunté si implementé la geometría incorrectamente y experimenté volteando los valores de coordenadas x / y en esta línea:
point.SetPoint(0, x, y)
..como..
point.SetPoint(0, y, x)
Sin embargo, eso no funcionó. Y no pensé en intentar cambiar los valores en la expresión Numpy de om_henners, creyendo erróneamente que cambiarlos en cualquier línea era equivalente. Creo que el verdadero problema se relaciona con las x_size
y y_size
los valores, respectivamente 30
y -30
, que se aplican cuando los índices de fila y de columna se utilizan para calcular las coordenadas del punto para las células.
[Edición original]
@om_henners, estoy probando su solución, en concierto con un par de recetas para hacer archivos de forma de puntos usando ogr ( invisibleroads.com , Chris Garrard ), pero tengo un problema en el que los puntos aparecen como si se reflejaran a través de una línea que pasa hasta 315/135 grados.
Puntos azules claros : creados por mi enfoque QGIS , arriba
Puntos morados : creados por el código py GDAL / OGR , a continuación
[Resuelto]
Este código de Python implementa la solución completa propuesta por @om_henners. Lo he probado y funciona. ¡Gracias hombre!
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())
(en lugar de tener que crear una proyección a partir de una cadena de proyecto conocida).