psycopg2를 사용하여 postgis에서 파이썬으로 래스터 데이터 다운로드


13

postgres 테이블에 래스터 데이터가있어 파이썬에 numpy 배열로 가져 가고 싶습니다. psycopg2를 사용하여 DB에 연결하고 있습니다. 데이터를 다운로드 할 수 있지만 문자열 (아마도 직렬화 된 이진)로 돌아옵니다.

이 문자열을 가져 와서 numpy 배열로 변환하는 방법을 아는 사람이 있습니까?

st_astiff를 사용하고 16 진수 파일을 다운로드하고 xxd를 사용하도록 인코딩하는 등 래스터를 다운로드하는 다른 옵션을 탐색했지만 작동하지 않습니다. 'rt_raster_to_gdal : 출력 GDAL 드라이버를로드 할 수 없습니다'라는 오류가 계속 발생하고 환경 변수를 설정하여 드라이버를 켤 수있는 권한이 없습니다.

TL, DR : 파이썬을 사용하여 래스터 데이터를 numpy 배열로 가져오고 싶습니다.

답변:


14

rt_raster_to_gdal : 출력 GDAL 드라이버를로드 할 수 없습니다

ST_AsTIFF 의 첫 번째 오류는 GDAL 드라이버를 활성화해야합니다. 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();

Numpy에 PostGIS

GDAL이 Numpy 배열로 읽을 수 있도록 출력을 가상 메모리 GeoTIFF 파일로 내보낼 수 있습니다. 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'를 사용하여 압축하십시오.


매우 도움이됩니다.
John Powell

매우 도움이됩니다. 감사! 여전히이 문제가 발생합니다 : 오류 : rt_raster_to_gdal : 출력 GDAL 드라이버를로드 할 수 없지만 해결 방법이 있다고 생각합니다. 다시 감사합니다!
Mayank Agarwal

@MayankAgarwal은 rt_raster_to_gdal 오류에 대한 답변을 업데이트했습니다.
Mike T

6

나는 gdal 드라이버를 사용하지 않고 postgis 래스터 테이블에서 읽을 수 있는지 여부가 문제라고 생각합니다. 파이썬으로 모든 것을 할 수 있습니다!

래스터 결과를 WKBinary로 선택하십시오.

St_AsBinary (rast) ...를 선택하십시오.

아래 스크립트를 사용하여 WKBinary를 파이썬 이미지 형식으로 해독하십시오. opencv는 임의의 수의 이미지 밴드를 처리하기 때문에 선호하지만 1 또는 3 개의 밴드가 더 일반적이면 PIL / low를 사용할 수 있습니다.

지금은 바이트 이미지 만 처리하지만 다른 데이터 유형으로 확장하는 것은 비교적 쉽지 않습니다.

이것이 유용하기를 바랍니다.

구조체 가져 오기
numpy를 np로 가져 오기
수입 cv2

# WKB 헤더를 해독하는 기능
데프 wkbHeader (원시) :
    # http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKnownBinaryFormat 참조

    헤더 = {}

    header [ 'endianess'] = struct.unpack ( 'B', 원시 [0]) [0]
    헤더 [ 'version'] = struct.unpack ( 'H', raw [1 : 3]) [0]
    header [ 'nbands'] = struct.unpack ( 'H', raw [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', raw [57:59]) [0]
    header [ 'height'] = struct.unpack ( 'H', raw [59:61]) [0]

    반환 헤더

# WKB 래스터 데이터를 해독하는 기능 
데프 wkbImage (원시) :
    h = wkbHeader (원시)
    img = [] # 이미지 밴드를 저장하는 배열
    offset = 61 # 헤더 원시 길이 (바이트)
    범위 (i [ 'nbands'])의 i :
        #이 밴드에 대한 pixtype 결정
        pixtype = struct.unpack ( 'B', raw [offset]) [0] >> 4
        # 지금은 부호없는 바이트 만 처리합니다.
        pixtype == 4 : 인 경우
            band = np.frombuffer (raw, dtype = 'uint8', count = h [ 'width'] * h [ 'height'], offset = offset + 1)
            img.append ((np.reshape (band, ((h [ 'height'], h [ 'width'])))))
            오프셋 = 오프셋 + 2 + h [ 'width'] * h [ 'height']
        할 일 : 다른 데이터 형식 처리 

    cv2.merge (tuple (img))를 반환


매우 도움이됩니다. 나는 conda 환경에서 gdal과 관련하여 많은 문제를 겪어 왔지만이 접근법은 처음에는 효과가 있었으며 구조에 약간의 탐구도 가능합니다.
존 파월
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.