Psycopg2 kullanarak postgis'ten raster verilerini python'a indirme


13

Ben bir numpy dizi olarak python almak istiyorum postgres tabloda raster veri var. Ben db bağlamak için psycopg2 kullanıyorum. Veri indirmek mümkün ama bir dize (muhtemelen serileştirilmiş bir ikili) olarak geri geliyor.

Bu dizeyi alıp numpy dizisine nasıl dönüştüğünü bilen var mı?

Hex dosyasını indirmek ve xxd kullanmak için st_astiff kullanın ve kodlamak gibi raster indirmek için diğer seçenekleri araştırdım ama işe yaramadı. 'Rt_raster_to_gdal: Çıkış GDAL sürücüsü yüklenemedi' hatasını almaya devam ediyorum ve ortam değişkenlerini sürücüleri açabilmek için ayarlama iznim yok.

TL, DR: Raster verilerini sayısal bir diziye (python kullanarak) aktarmak istiyorum.

Yanıtlar:


14

rt_raster_to_gdal: Çıkış GDAL sürücüsü yüklenemedi

ST_AsTIFF ile ilgili ilk hataya gelince , PostGIS 2.1 için varsayılan olarak etkin olmayan GDAL sürücülerinizi etkinleştirmeniz gerekir. Bunu yapmanın yolları hakkında kılavuza bakın . Örneğin, aşağıdakileri içeren bir Windows bilgisayarında ayarlanmış bir ortam değişkenim var:

POSTGIS_GDAL_ENABLED_DRIVERS=GTiff PNG JPEG GIF XYZ DTED USGSDEM AAIGrid

PostGIS ile aşağıdakilerle teyit edilebilir:

SELECT short_name, long_name
FROM ST_GDALDrivers();

PostGIS'den Numpy'ye

GDAL'ın Numpy dizisine okuması için çıktıyı sanal bellek GeoTIFF dosyasına aktarabilirsiniz. GDAL'da kullanılan sanal dosyalar hakkında ipuçları için bu blog yayınına bakın .

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

Rasterleştirilmiş bir arabellek noktası gösterir.

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

Örnekte bir 'GTiff' biçimi kullandığımı, ancak diğer biçimlerin daha uygun olabileceğini unutmayın. Örneğin, yavaş bir internet bağlantısı üzerinden aktarılması gereken büyük bir tarama cihazınız varsa, sıkıştırmak için 'PNG'yi kullanmayı deneyin.


Bu çok faydalı.
John Powell

Çok yararlı. Teşekkürler! Ben hala bu sorunla karşılaşıyorum: HATA: rt_raster_to_gdal: Çıkış GDAL sürücüsü yüklenemedi ama bunun için bir geçici çözüm olduğunu düşünüyorum. Tekrar teşekkürler!
Mayank Agarwal

@MayankAgarwal rt_raster_to_gdal hatası için cevabı güncelledi.
Mike T

6

Soru, gda sürücüleri etkin OLMADAN postgis raster tablolarından okunup okunamayacağıydı. Her şey gibi Python da yapabilirsiniz!

Raster sonucunuzu WKBinary olarak seçtiğinizden emin olun:

St_AsBinary (rast) seçin ...

WKBinary'i bir python görüntü formatına dönüştürmek için aşağıdaki komut dosyasını kullanın. Opencv'i tercih ederim, çünkü rasgele sayıda görüntü bandını işliyor, ancak 1 veya 3 bant daha normalse PIL / düşük kullanılabilir.

Şimdilik sadece bayt görüntülerini idare ediyorum, ancak diğer veri türlerine genişlemek nispeten önemsiz.

Umarım faydalıdır.

ithalat yapısı
np'yi np olarak içe aktar
ithalat cv2

# WKB üstbilgisini deşifre etme işlevi
def wkbHeader (ham):
    # Bkz. Http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKnownBinaryFormat

    başlık = {}

    başlık ['endianess'] = struct.unpack ('B', ham [0]) [0]
    başlık ['sürüm'] = struct.unpack ('H', ham [1: 3]) [0]
    header ['nbands'] = struct.unpack ('H', ham [3: 5]) [0]
    başlık ['scaleX'] = struct.unpack ('d', ham [5:13]) [0]
    başlık ['scaleY'] = struct.unpack ('d', ham [13:21]) [0]
    başlık ['ipX'] = struct.unpack ('d', ham [21:29]) [0]
    başlık ['ipY'] = struct.unpack ('d', ham [29:37]) [0]
    başlık ['skewX'] = struct.unpack ('d', ham [37:45]) [0]
    başlık ['skewY'] = struct.unpack ('d', ham [45:53]) [0]
    header ['srid'] = struct.unpack ('i', ham [53:57]) [0]
    başlık ['width'] = struct.unpack ('H', ham [57:59]) [0]
    başlık ['height'] = struct.unpack ('H', ham [59:61]) [0]

    dönüş başlığı

# WKB tarama verilerini deşifre etme işlevi 
def wkbImage (ham):
    h = wkbHeader (ham)
    img = [] Görüntü dizilerini saklamak için # dizi
    ofset = 61 # bayt cinsinden üstbilgi ham uzunluğu
    aralıktaki i için (h ['nbands']):
        # Bu grup için piksel türünü belirle
        pixtype = struct.unpack ('B', ham [ofset]) [0] >> 4
        # Şimdilik sadece imzasız baytlarla ilgileniyoruz
        pixtype == 4 ise:
            band = np.frombuffer (ham, dtype = 'uint8', sayım = h ['genişlik'] * h ['yükseklik'], ofset = ofset + 1)
            img.append ((np.reshape (bant, ((h ['yükseklik'], h ['genişlik'])))))
            ofset = ofset + 2 + h ['genişlik'] * h ['yükseklik']
        # to do: diğer veri türlerini işleme 

    return cv2.merge (grup (img))


Bu çok faydalı. Conda ortamında gdal ile ilgili birçok sorun yaşıyorum, ancak bu yaklaşım ilk kez çalıştı ve yapıya biraz da girebilmek güzel.
John Powell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.