15 votos

La descarga de una trama de datos en python desde postgis utilizando psycopg2

Tengo una trama de datos en una tabla de postgres que quiero conseguir en python como una colección de la matriz. Estoy usando psycopg2 para conectarse a la base de datos. Soy capaz de descargar los datos, pero se vuelve como una cadena (probablemente serializado binario). Hace cualquiera sabe cómo tomar esta cadena y convertir a una colección de la matriz.

He explorado otras opciones para descargar la trama, tales como el uso de st_astiff y codificar para descargar el archivo hex y el uso xxd pero que no funcionó. Sigo recibiendo el error 'rt_raster_to_gdal: no se Pudo cargar la salida de GDAL driver' y no tengo permisos para establecer las variables de entorno para poder activar los controladores.

Cualquier ayuda será apreciada.

TL, DR: desea importar los datos ráster en una colección de la matriz (usando python).

15voto

hernan43 Puntos 566

rt_raster_to_gdal: no se Pudo cargar la salida de GDAL conductor

En cuanto al primer error con ST_AsTIFF, necesita habilitar su GDAL los conductores, que por defecto no están habilitados para PostGIS 2.1. Consulte el manual de maneras de hacer esto. Por ejemplo, yo tengo una variable de entorno configurar en un equipo Windows con:

POSTGIS_GDAL_ENABLED_DRIVERS=GTiff PNG JPEG GIF XYZ DTED USGSDEM AAIGrid

lo que puede ser confirmado con PostGIS con:

SELECT short_name, long_name
FROM ST_GDALDrivers();

PostGIS para Numpy

Puede exportar los resultados a una memoria virtual GeoTIFF archivo para GDAL para leer en una Colección de la matriz. Para obtener más información sobre archivos virtuales utilizados en GDAL, ver esta entrada del blog.

import os
import psycopg2
from osgeo import gdal

# Adjust this to connect to a PostGIS database
conn = psycopg2.connect(...)
curs = conn.cursor()

# Make a dummy table with raster data
curs.execute("""\
    SELECT ST_AsRaster(ST_Buffer(ST_Point(1, 5), 10), 10, 10, '8BUI', 1) AS rast
    INTO TEMP mytable;
""")

# Use a virtual memory file, which is named like this
vsipath = '/vsimem/from_postgis'

# Download raster data into Python as GeoTIFF, and make a virtual file for GDAL
curs.execute("SELECT ST_AsGDALRaster(rast, 'GTiff') FROM mytable;")
gdal.FileFromMemBuffer(vsipath, bytes(curs.fetchone()[0]))

# Read first band of raster with GDAL
ds = gdal.Open(vsipath)
band = ds.GetRasterBand(1)
arr = band.ReadAsArray()

# Close and clean up virtual memory file
ds = band = None
gdal.Unlink(vsipath)

print(arr)  # this is a 2D numpy array

Muestra una rasterised búfer punto.

[[0 0 0 1 1 1 1 0 0 0]
 [0 1 1 1 1 1 1 1 1 0]
 [0 1 1 1 1 1 1 1 1 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]
 [0 1 1 1 1 1 1 1 1 0]
 [0 1 1 1 1 1 1 1 1 0]
 [0 0 0 1 1 1 1 0 0 0]]

Tenga en cuenta que he usado un 'GTiff' formato en el ejemplo, pero en otros formatos, podría ser más adecuado. Por ejemplo, si usted tiene una gran trama que necesita ser transferido a través de una conexión lenta a internet, trate de usar 'PNG' a comprimirlo.

6voto

Max Puntos 11

Creo que la pregunta era si se puede leer a partir de postgis raster de tablas, SIN gdal conductores habilitados. Como todas las cosas de Python, usted puede!

Asegúrese de seleccionar su trama resultado como WKBinary:

seleccione St_AsBinary(rast)...

Utilizar el siguiente script para decypher WKBinary en python formato de imagen. Yo prefiero opencv, debido a que se maneja un número arbitrario de la imagen de las bandas, pero se puede utilizar PIL/baja si 1 o 3 bandas son más habituales.

Yo solo byte identificador de imágenes por ahora, pero es relativamente trivial para ampliar a otros tipos de datos.

Espero que esto sea útil.


importación struct
import numpy como np
importación cv2

# Función para decypher la WKB encabezado
def wkbHeader(raw):
 # Vea http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKnownBinaryFormat

 header = {}

 encabezado ['"endian"'] = struct.desempaquetar('B', raw[0])[0]
 encabezado['versión'] = struct.desempaquetar('H', raw[1:3])[0]
 encabezado['nbands'] = struct.desempaquetar('H', raw[3:5])[0]
 encabezado['scaleX'] = struct.desempaquetar('d', raw[5:13])[0]
 encabezado['scaleY'] = struct.desempaquetar('d', raw[13:21])[0]
 encabezado['ipX'] = struct.desempaquetar('d', raw[21:29])[0]
 encabezado['ipY'] = struct.desempaquetar('d', raw[29:37])[0]
 encabezado['skewX'] = struct.desempaquetar('d', raw[37:45])[0]
 encabezado['skewY'] = struct.desempaquetar('d', raw[45:53])[0]
 encabezado['srid'] = struct.desempaquetar('i', raw[53:57])[0]
 encabezado['ancho'] = struct.desempaquetar('H', raw[57:59])[0]
 encabezado['altura'] = struct.desempaquetar('H', raw[59:61])[0]

 el cabezal de retorno

# Función para decypher la WKB datos ráster 
def wkbImage(raw):
 h = wkbHeader(raw)
 img = [] # matriz para almacenar la imagen de bandas
 offset = 61 # encabezado raw longitud en bytes
 for i in range(h['nbands']):
 # Determinar pixtype para esta banda
 pixtype = struct.desempaquetar('B', raw[offset])[0]>>4
 # Por ahora, que sólo se ocupan de bytes sin signo
 si pixtype == 4:
 banda = np.frombuffer(raw, dtype='uint8', count=h['ancho']*h['altura'], offset=offset+1)
 img.append((np.reformar(de la banda, ((h['altura'], h['ancho'])))))
 offset = offset + 2 + h['ancho']*h['altura']
 # hacer: manejar otros tipos de datos 

 volver cv2.merge(tupla(img))

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