Tải dữ liệu raster vào python từ postgis bằng psycopg2


13

Tôi có dữ liệu raster trong một bảng postgres mà tôi muốn vào python như một mảng numpy. Tôi đang sử dụng psycopg2 để kết nối với db. Tôi có thể tải xuống dữ liệu nhưng nó trở lại dưới dạng một chuỗi (có thể là nhị phân nối tiếp).

Có ai biết làm thế nào để lấy chuỗi này và chuyển đổi thành một mảng numpy?

Tôi đã khám phá các tùy chọn khác để tải xuống raster như sử dụng st_astiff và mã hóa để tải xuống tệp hex và sử dụng xxd nhưng điều đó không hiệu quả. Tôi tiếp tục gặp lỗi 'rt_raster_to_gdal: Không thể tải trình điều khiển GDAL đầu ra' và tôi không có quyền đặt các biến môi trường để có thể bật trình điều khiển.

TL, DR: muốn nhập dữ liệu raster vào một mảng numpy (sử dụng python).

Câu trả lời:


14

rt_raster_to_gdal: Không thể tải trình điều khiển GDAL đầu ra

Đối với lỗi đầu tiên với ST_AsTIFF , bạn cần kích hoạt trình điều khiển GDAL, theo mặc định không được bật cho PostGIS 2.1. Xem hướng dẫn về cách để làm điều này. Chẳng hạn, tôi có một biến môi trường được thiết lập trên máy tính Windows với:

POSTGIS_GDAL_ENABLED_DRIVERS=GTiff PNG JPEG GIF XYZ DTED USGSDEM AAIGrid

có thể được xác nhận với PostGIS với:

SELECT short_name, long_name
FROM ST_GDALDrivers();

PostGIS để Numpy

Bạn có thể xuất đầu ra sang tệp GeoTIFF của bộ nhớ ảo để GDAL đọc thành mảng Numpy. Để biết gợi ý về các tệp ảo được sử dụng trong GDAL, hãy xem bài đăng trên blog này .

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

Hiển thị một điểm đệm rasterised.

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

Lưu ý rằng tôi đã sử dụng định dạng 'GTiff' trong ví dụ, nhưng các định dạng khác có thể phù hợp hơn. Ví dụ: nếu bạn có một raster lớn cần truyền qua kết nối internet chậm, hãy thử sử dụng 'PNG' để nén nó.


Điều đó rất hữu ích.
John Powell

Rất hữu ích. cảm ơn! Tôi vẫn đang gặp phải vấn đề này: ERROR: rt_raster_to_gdal: Không thể tải trình điều khiển GDAL đầu ra nhưng tôi nghĩ rằng tôi có một cách giải quyết cho điều đó. cảm ơn lần nữa
Mayank Agarwal

@MayankAgarwal cập nhật câu trả lời cho lỗi rt_raster_to_gdal.
Mike T

6

Tôi nghĩ rằng câu hỏi là liệu bạn có thể đọc từ các bảng raster postgis mà KHÔNG kích hoạt trình điều khiển gdal không. Như tất cả mọi thứ Python, bạn có thể!

Đảm bảo bạn chọn kết quả raster của mình là WKBinary:

chọn St_AsBinary (rast) ...

Sử dụng tập lệnh bên dưới để giải mã WKBinary thành định dạng hình ảnh python. Tôi thích opencv hơn, vì nó xử lý số lượng dải hình ảnh tùy ý, nhưng người ta có thể sử dụng PIL / low nếu 1 hoặc 3 băng tần thường hơn.

Bây giờ tôi chỉ xử lý hình ảnh byte, nhưng việc mở rộng sang các kiểu dữ liệu khác là tương đối tầm thường.

Hy vọng điều này là hữu ích.

cấu trúc nhập khẩu
nhập numpy như np
nhập cv2

# Chức năng giải mã tiêu đề WKB
def wkbHeader (thô):
    # Xem http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKnownBinaryFormat

    tiêu đề = {}

    tiêu đề ['endianess'] = struct.unpack ('B', raw [0]) [0]
    tiêu đề ['phiên bản'] = struct.unpack ('H', raw [1: 3]) [0]
    tiêu đề ['nbands'] = struct.unpack ('H', raw [3: 5]) [0]
    tiêu đề ['scaleX'] = struct.unpack ('d', raw [5:13]) [0]
    tiêu đề ['scaleY'] = struct.unpack ('d', raw [13:21]) [0]
    tiêu đề ['ipX'] = struct.unpack ('d', raw [21:29]) [0]
    tiêu đề ['ipY'] = struct.unpack ('d', raw [29:37]) [0]
    tiêu đề ['skewX'] = struct.unpack ('d', raw [37:45]) [0]
    tiêu đề ['skewY'] = struct.unpack ('d', raw [45:53]) [0]
    tiêu đề ['srid'] = struct.unpack ('i', raw [53:57]) [0]
    tiêu đề ['width'] = struct.unpack ('H', raw [57:59]) [0]
    tiêu đề ['height'] = struct.unpack ('H', raw [59:61]) [0]

    tiêu đề trở lại

# Chức năng giải mã dữ liệu raster WKB 
def wkbImage (thô):
    h = wkbHhead (thô)
    img = [] # mảng để lưu trữ các dải hình ảnh
    offset = 61 # độ dài thô tiêu đề tính bằng byte
    cho i trong phạm vi (h ['nbands']):
        # Xác định pixtype cho ban nhạc này
        pixtype = struct.unpack ('B', raw [offset]) [0] >> 4
        # Hiện tại, chúng tôi chỉ xử lý byte không dấu
        nếu pixtype == 4:
            band = np.frombuffer (raw, dtype = 'uint8', Count = h ['width'] * h ['height'], offset = offset + 1)
            img.append ((np.reshape (ban nhạc, ((h ['height'], h ['width'])))))
            offset = offset + 2 + h ['width'] * h ['height']
        # để làm: xử lý các loại dữ liệu khác 

    trả về cv2.merge (tuple (img))


Điều đó rất hữu ích. Tôi đã gặp rất nhiều vấn đề với gdal trong môi trường conda, nhưng cách tiếp cận này đã có hiệu quả lần đầu tiên và thật tuyệt khi có thể đi sâu vào cấu trúc một chút.
John Powell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.