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).Respuestas:
En GDAL puede importar el ráster como una matriz numpy.
Luego, usar numpy es simple obtener los índices de una matriz que coincida con una expresión boolan:
Desde la geotransformación ráster podemos obtener información como las coordenadas x e y superior izquierda y los tamaños de celda.
La celda superior izquierda corresponde a
a[0, 0]
. El tamaño Y siempre será negativo, por lo que con los índices x e y puede calcular las coordenadas de cada celda en función de los índices.A partir de aquí, es bastante simple crear un archivo de forma usando OGR. Para obtener un código de muestra, consulte esta pregunta sobre cómo generar un nuevo conjunto de datos con información de puntos.
fuente
(y_index, x_index) = np.nonzero(a > threshold)
.shp
--- solo que no lo hizo trabajo, ni estaba cerca. No me sorprendió ya que el valor de x está en los cientos de miles, y la y está en millones, por lo que me dejó bastante confundido. No pensé en intentar darles la vuelta ante la expresión de Numpy. Muchas gracias por su ayuda, esto es genial. Exactamente lo que quería. :)¿Por qué no usar la caja de herramientas Sexante en QGIS? Es algo así como el Model Builder para ArcGIS. De esa manera, puede encadenar operaciones y tratarla como una operación. Puede automatizar la eliminación de archivos intermedios y la eliminación de registros no deseados si no me equivoco.
fuente
Puede ser útil importar los datos a postgis (con soporte de ráster) y usar las funciones allí. Este tutorial puede tener elementos que necesita.
fuente