39 votos

Escribir una matriz numpy en un archivo raster

Soy nuevo en el SIG.

Tengo un código que convierte imágenes infrarrojas de Marte en mapas de inercia térmica, que luego se almacenan como matrices 2D de numpy. He estado guardando estos mapas como archivos hdf5 pero realmente me gustaría guardarlos como imágenes raster para poder procesarlos en QGIS. He realizado múltiples búsquedas para encontrar cómo hacer esto pero sin suerte. He intentado seguir las instrucciones del tutorial en http://www.gis.usu.edu/~chrisg/python/ pero los archivos que produzco usando su código de ejemplo se abren como simples cajas grises cuando los importo a QGIS. Creo que si alguien pudiera sugerir el procedimiento más sencillo posible para un ejemplo simplificado de lo que me gustaría hacer, entonces podría ser capaz de hacer algún progreso. Tengo QGIS y GDAL, estaría encantado de instalar otros frameworks que alguien pudiera recomendar. Uso Mac OS 10.7.

Así que si por ejemplo tengo un array de numpy de inercia térmica que se parece a:

TI = ( (0.1, 0.2, 0.3, 0.4),
       (0.2, 0.3, 0.4, 0.5),
       (0.3, 0.4, 0.5, 0.6),
       (0.4, 0.5, 0.6, 0.7) )

Y para cada píxel tengo la latitud y la longitud:

lat = ( (10.0, 10.0, 10.0, 10.0),
        ( 9.5,  9.5,  9.5,  9.5),
        ( 9.0,  9.0,  9.0,  9.0),
        ( 8.5,  8.5,  8.5,  8.5) )
lon = ( (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5) ) 

¿Qué procedimiento me recomiendan para convertir estos datos en un archivo raster que pueda abrir en QGIS?

0 votos

¿A qué diapositiva del tutorial se refiere?

1 votos

Me encanta Python, pero veo tantas respuestas como estas de abajo que serían de una sola línea en R.

0 votos

¿Alguien ha probado aquí el método Create con la opción AAIGrid? O incluso con AIG. No crea el objeto output_raster. Tampoco se lanza ningún error. Los metadatos parecen estar bien para crear un objeto Create pero siempre obtengo NoneType. GTiff funciona bien Aquí está el fragmento de código que he probado: ``` xmin,ymin,xmax,ymax = [lons.min().values,lats.min().values,\ lons.max().values,lats.max().values] ncols =lons.shape[0] nrows = lats. shape[0] xres = (xmax-xmin)/float(ncols) yres = (ymax-ymin)/float(nrows) geotransform=[xmin,xres,0,ymin,0,yres ] driver= gdal.GetDriverByName('AAIGrid') metadata = driver.GetMetadata() outp

34voto

Josh Puntos 569

Abajo hay un ejemplo que escribí para un taller que utiliza los módulos de Python numpy y gdal. Lee los datos de un archivo .tif en un array de numpy, hace una reclasificación de los valores en el array y luego los escribe de nuevo en un .tif.

Por tu explicación, parece que has conseguido escribir un archivo válido, pero sólo necesitas simbolizarlo en QGIS. Si no recuerdo mal, cuando se añade por primera vez un raster, a menudo aparece todo de un solo color si no se tiene un mapa de colores preexistente.

import numpy, sys
from osgeo import gdal
from osgeo.gdalconst import *

# register all of the GDAL drivers
gdal.AllRegister()

# open the image
inDs = gdal.Open("c:/workshop/examples/raster_reclass/data/cropland_40.tif")
if inDs is None:
  print 'Could not open image file'
  sys.exit(1)

# read in the crop data and get info about it
band1 = inDs.GetRasterBand(1)
rows = inDs.RasterYSize
cols = inDs.RasterXSize

cropData = band1.ReadAsArray(0,0,cols,rows)

listAg = [1,5,6,22,23,24,41,42,28,37]
listNotAg = [111,195,141,181,121,122,190,62]

# create the output image
driver = inDs.GetDriver()
#print driver
outDs = driver.Create("c:/workshop/examples/raster_reclass/output/reclass_40.tif", cols, rows, 1, GDT_Int32)
if outDs is None:
    print 'Could not create reclass_40.tif'
    sys.exit(1)

outBand = outDs.GetRasterBand(1)
outData = numpy.zeros((rows,cols), numpy.int16)

for i in range(0, rows):
    for j in range(0, cols):

    if cropData[i,j] in listAg:
        outData[i,j] = 100
    elif cropData[i,j] in listNotAg:
        outData[i,j] = -100
    else:
        outData[i,j] = 0

# write the data
outBand.WriteArray(outData, 0, 0)

# flush data to disk, set the NoData value and calculate stats
outBand.FlushCache()
outBand.SetNoDataValue(-99)

# georeference the image and set the projection
outDs.SetGeoTransform(inDs.GetGeoTransform())
outDs.SetProjection(inDs.GetProjection())

del outData

2 votos

+1 por tirar de la cadena ¡me estaba dando la cabeza contra la pared tratando de averiguar cómo "salvar" la cosa!

1 votos

Tuve que añadir outDs = None para que se guarde

29voto

MoL Puntos 11

Finalmente he dado con esta solución, que obtuve de esta discusión ( http://osgeo-org.1560.n6.nabble.com/gdal-dev-numpy-array-to-raster-td4354924.html ). Me gusta porque puedo pasar directamente de un array de numpy a un archivo tif raster. Estaría muy agradecido por los comentarios que puedan mejorar la solución. Lo publicaré aquí por si alguien más busca una respuesta similar.

import numpy as np
from osgeo import gdal
from osgeo import gdal_array
from osgeo import osr
import matplotlib.pylab as plt

array = np.array(( (0.1, 0.2, 0.3, 0.4),
                   (0.2, 0.3, 0.4, 0.5),
                   (0.3, 0.4, 0.5, 0.6),
                   (0.4, 0.5, 0.6, 0.7),
                   (0.5, 0.6, 0.7, 0.8) ))
# My image array      
lat = np.array(( (10.0, 10.0, 10.0, 10.0),
                 ( 9.5,  9.5,  9.5,  9.5),
                 ( 9.0,  9.0,  9.0,  9.0),
                 ( 8.5,  8.5,  8.5,  8.5),
                 ( 8.0,  8.0,  8.0,  8.0) ))
lon = np.array(( (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5) ))
# For each pixel I know it's latitude and longitude.
# As you'll see below you only really need the coordinates of
# one corner, and the resolution of the file.

xmin,ymin,xmax,ymax = [lon.min(),lat.min(),lon.max(),lat.max()]
nrows,ncols = np.shape(array)
xres = (xmax-xmin)/float(ncols)
yres = (ymax-ymin)/float(nrows)
geotransform=(xmin,xres,0,ymax,0, -yres)   
# That's (top left x, w-e pixel resolution, rotation (0 if North is up), 
#         top left y, rotation (0 if North is up), n-s pixel resolution)
# I don't know why rotation is in twice???

output_raster = gdal.GetDriverByName('GTiff').Create('myraster.tif',ncols, nrows, 1 ,gdal.GDT_Float32)  # Open the file
output_raster.SetGeoTransform(geotransform)  # Specify its coordinates
srs = osr.SpatialReference()                 # Establish its coordinate encoding
srs.ImportFromEPSG(4326)                     # This one specifies WGS84 lat long.
                                             # Anyone know how to specify the 
                                             # IAU2000:49900 Mars encoding?
output_raster.SetProjection( srs.ExportToWkt() )   # Exports the coordinate system 
                                                   # to the file
output_raster.GetRasterBand(1).WriteArray(array)   # Writes my array to the raster

output_raster.FlushCache()

3 votos

La "rotación está en dos veces" para tener en cuenta el efecto de un bit girado de y en x y el bit girado de x en y. Ver lists.osgeo.org/pipermail/gdal-dev/2011-Julio/029449.html que trata de explicar las interrelaciones entre los parámetros de "rotación".

0 votos

Este post es realmente útil, gracias. En mi caso, sin embargo, estoy recibiendo un archivo tif que es completamente negro cuando lo abro como una imagen fuera de ArcGIS. Mi referencia espacial es la cuadrícula nacional británica (EPSG=27700), y las unidades son metros.

0 votos

He publicado una pregunta aquí: gis.stackexchange.com/questions/232301/

28voto

rkthkr Puntos 6651

Una posible solución a su problema: convertirlo en un ASCII Raster, cuya documentación está aquí . Esto debería ser bastante fácil de hacer con python.

Así, con los datos de tu ejemplo anterior, terminarías con lo siguiente en un archivo .asc:

ncols 4
nrows 4
xllcorner 20
yllcorner 8.5
cellsize 0.5
nodata_value -9999
0.1 0.2 0.3 0.4
0.2 0.3 0.4 0.5
0.3 0.4 0.5 0.6
0.4 0.5 0.6 0.7

Esto se añade con éxito tanto a QGIS como a ArcGIS, y estilizado en ArcGIS se ve así: raster version of above

Adición: Aunque se puede añadir a QGIS como se ha indicado, si se intenta entrar en sus propiedades (para estilizarlo), QGIS 1.8.0 se cuelga. Estoy a punto de reportar esto como un bug. Si esto también te ocurre, hay muchos otros SIG gratuitos por ahí.

0 votos

Es fantástico, gracias. Y me imagino que habiendo escrito mi matriz como un archivo ascii podría convertirlo en un formato binario usando una función de conversión preescrita.

0 votos

Para tu información, no he tenido el problema de cuelgue con QGIS, también tengo la versión 1.8.0.

0 votos

Hola, ¿hay algún enlace donde pueda encontrar cómo convertir mi array de numpy a ASCII, para que el archivo final lo obtenga geotiff para trazar.

9voto

phill Puntos 18

Una alternativa al enfoque sugerido en las otras respuestas es utilizar el rasterio paquete. Tuve problemas al generar estos usando gdal y encontró este sitio para ser útil.

Suponiendo que tengas otro archivo tif( other_file.tif ) y una matriz numpy ( numpy_array ) que tiene la misma resolución y extensión que este archivo, este es el enfoque que me funcionó:

import rasterio as rio    

with rio.open('other_file.tif') as src:
    ras_data = src.read()
    ras_meta = src.profile

# make any necessary changes to raster properties, e.g.:
ras_meta['dtype'] = "int32"
ras_meta['nodata'] = -99

with rio.open('outname.tif', 'w', **ras_meta) as dst:
    dst.write(numpy_array, 1)

8voto

Gustav Puntos 140

También hay un buena solución en el libro oficial GDAL/OGR Cookbook for Python.

Esta receta crea una trama a partir de una matriz

import gdal, ogr, os, osr
import numpy as np

def array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):

    cols = array.shape[1]
    rows = array.shape[0]
    originX = rasterOrigin[0]
    originY = rasterOrigin[1]

    driver = gdal.GetDriverByName('GTiff')
    outRaster = driver.Create(newRasterfn, cols, rows, 1, gdal.GDT_Byte)
    outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
    outband = outRaster.GetRasterBand(1)
    outband.WriteArray(array)
    outRasterSRS = osr.SpatialReference()
    outRasterSRS.ImportFromEPSG(4326)
    outRaster.SetProjection(outRasterSRS.ExportToWkt())
    outband.FlushCache()

def main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
    reversed_arr = array[::-1] # reverse array so the tif looks like the array
    array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,reversed_arr) # convert array to raster

if __name__ == "__main__":
    rasterOrigin = (-123.25745,45.43013)
    pixelWidth = 10
    pixelHeight = 10
    newRasterfn = 'test.tif'
    array = np.array([[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])

    main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array)

0 votos

Esta receta es buena pero hay un problema con el archivo tiff final. Los valores lat-lon de los píxeles no son correctos.

1 votos

Es posible que se produzcan incompatibilidades extrañas entre ESRI WKT y OGC WKT: gis.stackexchange.com/questions/129764/

0 votos

Una cosa que encontré es que la forma mencionada por usted definitivamente cambiará el array a un raster con facilidad. Pero necesitamos georreferenciar este raster con la coordenada superior izquierda e inferior derecha usando gdal_translate. Una forma de hacerlo es siguiendo los dos pasos : 1) Primero encontrar los valores de latitud superior izquierda e inferior derecha a través de gdalinfo 2) Luego, a través de gdal_translate utilizar el geotiff (generado con el enfoque antes mencionado de convertir el array en raster) para georeferenciarlo con las coordenadas de latitud superior izquierda e inferior derecha.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X