Завантаження растрових даних у python з postgis за допомогою psycopg2


13

У таблиці постгресів є растрові дані, які я хочу потрапити в python як масивний ряд. Я використовую psycopg2 для підключення до db. Я можу завантажити дані, але вони повертаються як рядок (можливо, серіалізований двійковий).

Хтось знає, як взяти цей рядок і перетворити його на нумерований масив?

Я вивчив інші варіанти для завантаження растра, наприклад використання st_astiff і кодування, щоб завантажити шестигранний файл і використовувати xxd, але це не спрацювало. Я продовжую отримувати помилку "rt_raster_to_gdal: Не вдалося завантажити вихідний драйвер GDAL", і я не маю дозволів встановлювати змінні середовища, щоб мати можливість вмикати драйвери.

TL, DR: хочу імпортувати растрові дані в масив numpy (використовуючи python).

Відповіді:


14

rt_raster_to_gdal: Не вдалося завантажити вихідний драйвер GDAL

Що стосується першої помилки з ST_AsTIFF , вам потрібно включити ваші драйвери GDAL, які за замовчуванням не включені для PostGIS 2.1. Дивіться посібник щодо способів цього зробити. Наприклад, у мене на комп’ютері Windows встановлена ​​змінна середовище:

POSTGIS_GDAL_ENABLED_DRIVERS=GTiff PNG JPEG GIF XYZ DTED USGSDEM AAIGrid

що може бути підтверджено PostGIS за допомогою:

SELECT short_name, long_name
FROM ST_GDALDrivers();

PostGIS до Numpy

Ви можете експортувати вихід у файл GeoTIFF віртуальної пам'яті для GDAL для зчитування в масив Numpy. Про підказки щодо віртуальних файлів, використовуваних у GDAL, дивіться цю публікацію в блозі .

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

Показує розсіяну буферну точку.

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

Зауважте, що у прикладі я використовував формат "GTiff", але інші формати, можливо, краще підходять. Наприклад, якщо у вас є великий растр, який потрібно перенести через повільне підключення до Інтернету, спробуйте скористатися "PNG" для його стиснення.


Це дуже корисно.
Джон Пауелл

Дуже корисний. Дякую! Я все ще стикаюся з цим питанням, що: ПОМИЛКА: rt_raster_to_gdal: Не вдалося завантажити вихідний драйвер GDAL, але я думаю, у мене є вирішення цього питання. знову дякую!
Mayank Agarwal

@MayankAgarwal оновив відповідь на помилку rt_raster_to_gdal.
Майк Т

6

Я думаю, питання полягав у тому, чи можна читати з растрових таблиць postgis БЕЗ включених драйверів gdal. Як і все, Python, ви можете!

Переконайтесь, що ви вибрали свій растровий результат як WKBinary:

виберіть St_AsBinary (rast) ...

Скористайтеся сценарієм нижче, щоб розшифрувати WKBinary у формат зображення python. Я віддаю перевагу opencv, тому що він обробляє довільну кількість діапазонів зображень, але можна використовувати PIL / low, якщо звичайні 1 або 3 діапазони.

Наразі я обробляю лише байтові зображення, але порівняно тривіально розширюватися на інші типи даних.

Сподіваюся, це корисно.

імпорт структура
імпортувати numpy як np
імпорт cv2

# Функція для дешифрування заголовка WKB
def wkbHeader (raw):
    # Див. Http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKknownBinaryFormat

    header = {}

    header ['endianess'] = struct.unpack ('B', необроблений [0]) [0]
    header ['версія'] = struct.unpack ('H', необроблений [1: 3]) [0]
    header ['nbands'] = struct.unpack ('H', необроблений [3: 5]) [0]
    header ['scaleX'] = struct.unpack ('d', raw [5:13]) [0]
    header ['scaleY'] = struct.unpack ('d', raw [13:21]) [0]
    header ['ipX'] = struct.unpack ('d', raw [21:29]) [0]
    header ['ipY'] = struct.unpack ('d', raw [29:37]) [0]
    header ['skewX'] = struct.unpack ('d', raw [37:45]) [0]
    header ['skewY'] = struct.unpack ('d', raw [45:53]) [0]
    header ['srid'] = struct.unpack ('i', raw [53:57]) [0]
    header ['width'] = struct.unpack ('H', необроблений [57:59]) [0]
    header ['height'] = struct.unpack ('H', необроблений [59:61]) [0]

    зворотний заголовок

# Функція для дешифрування растрових даних WKB 
def wkbImage (raw):
    h = wkbHeader (необроблений)
    img = [] # масив для зберігання діапазонів зображень
    зміщення = 61 # заголовка необмеженої довжини в байтах
    для i в діапазоні (h ['nbands']):
        # Визначте піксельний тип для цього діапазону
        pixtype = struct.unpack ('B', необроблений [зсув]) [0] >> 4
        # Зараз ми обробляємо лише неподписаний байт
        якщо pixtype == 4:
            діапазон = np.frombuffer (raw, dtype = 'uint8', count = h ['width'] * h ['height'], offset = offset + 1)
            img.append ((np.reshape (смуга, ((h ['висота'], h ['ширина'))))))
            зміщення = зміщення + 2 + год ['ширина'] * год ['висота']
        # робити: обробляти інші типи даних 

    return cv2.merge (tuple (img))


Це дуже корисно. У мене було багато проблем з gdal у середовищі conda, але такий підхід спрацьовував уперше, і приємно також мати можливість трохи заглибитися в структуру.
Джон Пауелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.