使用Psycopg2从Postgis将栅格数据下载到python中


13

我在postgres表中有栅格数据,我想以numpy数组的形式进入python。我正在使用psycopg2连接到数据库。我可以下载数据,但它以字符串形式返回(可能是序列化的二进制文件)。

有谁知道如何获取此字符串并将其转换为numpy数组吗?

我探索了其他下载栅格的选项,例如使用st_astiff并编码以下载hex文件并使用xxd,但这没有用。我不断收到错误消息“ rt_raster_to_gdal:无法加载输出GDAL驱动程序”,并且我没有权限设置环境变量以能够打开驱动程序。

TL,DR:想将栅格数据导入numpy数组(使用python)。

Answers:


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”格式,但其他格式可能更适合。例如,如果您有较大的栅格需要通过缓慢的Internet连接传输,请尝试使用“ PNG”对其进行压缩。


那很有帮助。
约翰·鲍威尔

很有帮助。谢谢!我仍然遇到以下问题:错误:rt_raster_to_gdal:无法加载输出GDAL驱动程序,但我认为我有解决方法。再次感谢!
Mayank Agarwal,2015年

@MayankAgarwal更新了rt_raster_to_gdal错误的答案。
Mike T

6

我认为问题是,如果不启用gdal驱动程序,是否可以从Postgis栅格表中读取。就像Python一样,您可以!

确保将栅格结果选择为WKBinary:

选择St_AsBinary(rast)...

使用下面的脚本将WKBinary解密为python图像格式。我更喜欢opencv,因为它可以处理任意数量的图像带,但是如果更常用1或3个带,则可以使用PIL / low。

我现在只处理字节图像,但是扩展到其他数据类型相对来说并不容易。

希望这是有用的。

导入结构
将numpy导入为np
导入cv2

#解密WKB标头的函数
def wkbHeader(raw):
    #参见http://trac.osgeo.org/postgis/browser/trunk/raster/doc/RFC2-WellKnownBinaryFormat

    标头= {}

    header ['endianess'] = struct.unpack('B',raw [0])[0]
    header ['version'] = struct.unpack('H',raw [1:3])[0]
    标头['nbands'] = struct.unpack('H',raw [3:5])[0]
    header ['scaleX'] = struct.unpack('d',raw [5:13])[0]
    标头['scaleY'] = struct.unpack('d',raw [13:21])[0]
    标头['ipX'] = struct.unpack('d',raw [21:29])[0]
    标头['ipY'] = struct.unpack('d',raw [29:37])[0]
    标头['skewX'] = struct.unpack('d',raw [37:45])[0]
    标头['skewY'] = struct.unpack('d',raw [45:53])[0]
    标头['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栅格数据的功能 
def wkbImage(原始):
    h = wkbHeader(原始)
    img = []#存储图像波段的数组
    offset = 61#标头原始长度(以字节为单位)
    对于范围内的我(h ['nbands']):
        #确定该乐队的像素类型
        pixtype = struct.unpack('B',raw [offset])[0] >> 4
        #目前,我们只处理无符号字节
        如果pixtype == 4:
            band = np.frombuffer(原始,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的很多问题,但是这种方法第一次起作用了,并且能够深入研究该结构也很不错。
约翰·鲍威尔,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.