Más

Reclasificar ráster usando python, gdal y numpy

Reclasificar ráster usando python, gdal y numpy


Me gustaría reclasificar un archivo ráster de un ráster con 10 clases a un ráster con 8 clases usando Python, GDAL y / o numpy. Las clases se representan como números enteros. He intentado seguir los pasos de esta publicación. ¿Reclasificar rásteres usando GDAL y Python? , el documento numpy.equal y también gdal_calc doc. Sin embargo, fue en vano.

El archivo ráster que se reclasifica tiene valores enteros que van de 0 a 11 y también incluyen valores 100 y 255. A continuación, se muestra la reclasificación (de valor: a valor):

nodata: 4, 0: 4, 1: 1, 2: 2, 3: 3, 4: 3, 5: 4, 6: 5, 7: 5, 8: 6, 9: 7, 10: 8, 100: nodata, 255: nodata,

Lo que he podido hacer es seleccionar el archivo ráster que se va a reclasificar usando tkinter.FileDialog y obtener la información del ráster como geotransform y el tamaño de píxel con reclass = gdal.Open (raster, GA_ReadOnly).

¿Cómo hago para resolver lo anterior?

Vale la pena mencionar que los rásteres que se reclasificarán pueden ser bastante grandes en algunos casos (500 MB a 5 GB).


Aquí tienes un script de Python simple para la reclasificación, lo escribí y me funciona:

from osgeo import gdal driver = gdal.GetDriverByName ('GTiff') file = gdal.Open ('/ home / user / workspace / raster.tif') band = file.GetRasterBand (1) lista = band.ReadAsArray () # reclasificación para j en rango (archivo.RasterXSize): para i en rango (archivo.RasterYSize): si lista [i, j] <200: lista [i, j] = 1 elif 200 

Simplemente cambie los rangos.

Espero que te ayude.


En lugar de hacer la reclasificación como un bucle for doble descrito por dmh126, hágalo usandonp. donde:

# reclasificación lista [np.where (lista <200)] = 1 lista [np.where ((200  800)] = 5

En una matriz de 6163 por 3537 píxeles (41,6 MB), la clasificación se realiza en 1,59 segundos, donde se necesitan 12 minutos y 41 segundos utilizando el bucle doble for. En total, solo una aceleración de 478x.

En pocas palabras, nunca use un bucle for doble usandonumpy


Aquí hay un ejemplo básico usando rasterio y numpy:

importar rasterio como rio importar numpy como np con rio.open ('~ / rasterio / tests / data / rgb1.tif') como src: # Leer el ráster en una matriz (filas, columnas, profundidad), # d apilar esto en una (profundidad, filas, columnas) matriz, # la suma a lo largo del último eje (~ = escala de grises) gris = np.mean (np.dstack (src.read ()), eje = 2) # Leer el perfil del archivo srcprof = src .profile.copy () classes = 5 # Breaks es una matriz de los cortes de clase: [0. 51. 102. 153. 204.] breaks = (np.arange (clases) / float (clases)) * grey.max () # clasifica el ráster clasificado = np.sum (np.dstack ([(gris 

Solo para completar la respuesta de @Mattijn, creo que generará un problema si las clases de entrada se superponen con las clases de salida. No quiero que la siguiente regla cambie mi nuevo valor.

No sé si pierdo velocidad pero debería hacer una copia profunda:

list_dest = lista.copy () list_dest [np.where (lista <0)] = 0 list_dest [np.where ((0 <= lista) & (lista <= 1))] = 1 list_dest [np.where (( 1 

En algunos casos, la digitalización numérica puede ser útil para pasar rápidamente de rangos a contenedores.

importar rasterio import numpy as np con rasterio.open ('my_raster.tif') as src: array = src.read () profile = src.profile bins = np.array ([- 1., - 0.7, -0.4, 0.2 , 1]) inds = np.digitize (matriz, bins) con rasterio.open ('output_raster.tif', 'w', ** perfil) como dst: dst.write (inds)

Aquí hay otro enfoque de Rasterio que pirateé usando el Libro de cocina de Rasterio y la respuesta de @ Mattijn.

importar rasterio importar numpy como np con rasterio.open ('input_raster.tif') como src: # Leer como matriz numpy matriz = src.read () perfil = src.profile # Reclasificar matriz [np.donde (matriz == 0) ] = 4 matriz [np.where (matriz == 2)] = 1 # y así sucesivamente… con rasterio.open ('output_raster.tif', 'w', ** perfil) como dst: # Escribir en disco dst. escribir (matriz)

Con soporte de tabla de colores ráster RGB:

import numpy as np from osgeo import gdal path_inDs = "/data/OCS_2016.extract.tif" path_outDs = "/data/OCS_2016.postpython.tif" driver = gdal.GetDriverByName ('GTiff') file = gdal.Open (path_inDs) si el archivo es None: print ('No se pudo abrir el archivo de imagen') sys.exit (1) band = file.GetRasterBand (1) lista = band.ReadAsArray () # reclasificación lista [np.where (lista == 31)] = 16 # crear un nuevo archivo file2 = driver.Create (path_outDs, file.RasterXSize, file.RasterYSize, 1, gdal.GPI_RGB) file2.GetRasterBand (1) .WriteArray (lista) # sistema de ref. georef = archivo.GetGeoTransform () meta = archivo.GetMetadata () colores = archivo.GetRasterBand (1) .GetRasterColorTable () archivo2.SetProjection (proj) archivo2.SetGeoTransform (georef) archivo2.SetMetadata (meta) archivo2.GetRasterBand (1) .SetRasterColorTable (colores) archivo2.FlushCache () del archivo2

Una alternativa ligeramente diferente podría ser la siguiente:

import numpy as np from osgeo import gdal original = gdal.Open ('** PATH **  origianl_raster.tif') # leer el archivo original band = original.GetRasterBand (1) # asumiendo que el archivo tiene solo una banda band_array = band.ReadAsArray () #crear una nueva matriz con valores reclasificados new_array = np.where (band_array == np.nan, 4, np.where (band_array == 0, 4, np.where (band_array == 1, 1 , np.where (band_array == 2, 2, np.where (band_array == 3, 3, np.where (band_array == 4, 3, np.where (band_array == 5, 4, np.where (band_array == 6, 5, np.where (band_array == 7, 5, np.where (band_array == 8, 6, np.where (band_array == 9, 7, np.where (band_array == 10, 8, np.where (band_array == 100, np.nan, np.nan))))))))))))) # la última línea también incluye valores iguales a 255, ya que son los únicos que quedan # create y guardar el ráster reclasificado como un archivo nuevo outDs = gdal.GetDriverByName ('GTiff'). Create ("** PATH **  reclassified_raster.tif", original.RasterXSize, original.RasterYSize, 1, gdal.GDT_Float32) outBand = outDs .GetRast erBand (1) outBand.WriteArray (new_array) outDs.SetGeoTransform (original.GetGeoTransform ()) outDs.SetProjection (original.GetProjection ()) # vaciar caché outDs.FlushCache ()

Este script juega con numpy.where (https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html): en todos los pasos excepto el último, en lugar de devolver un valor cuando el la condición no se cumple, devuelve otro np. donde. Y continúa hasta que se consideran todos los valores posibles del ráster.


Aquí hay un enfoque para la reclasificación arbitraria de rásteres enteros que evita el uso de un millón de llamadas anp. donde. Bits de Rasterio tomados de la respuesta de @ Aaron:

import rasterio import numpy as np # Construye una "matriz de búsqueda" donde el índice es el valor original y el valor # es el valor reclasificado. Establecer todos los valores reclasificados es barato # porque la memoria solo se asigna una vez para la matriz de búsqueda. lookup = np.arange (255, dtype = np.uint8) lookup [5] = 10 lookup [6] = 100 lookup [7] = 200 con rasterio.open ('input_raster.tif') como src: # Leer como numpy array array = src.read () profile = src.profile # Reclasificar en una sola operación usando broadcasting array = lookup [array] con rasterio.open ('output_raster.tif', 'w', ** profile) como dst: # Escribir en el disco dst.write (matriz)

Ver el vídeo: Python GIS - Open raster and get information GDAL