Answers:
至于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();
您可以将输出导出到虚拟内存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”对其进行压缩。
我认为问题是,如果不启用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))