对于大多数用例,您将通过使用打包的 raster2pgsql
栅格加载器加载现有栅格文件来创建 PostGIS 栅格。
raster2pgsql
是一个用于将 GDAL 支持的栅格格式加载到适合加载到 PostGIS 栅格表的 SQL 的栅格加载器可执行文件。它能够加载文件夹中的栅格文件,同时创建栅格的概览。
由于 raster2pgsql 最常被编译为 PostGIS 的一部分(除非您编译自己的 GDAL 库),因此可执行文件支持的栅格类型将与 GDAL 依赖库中编译的栅格类型相同。 要获取特定 raster2pgsql
支持的栅格类型列表,请使用 -G
指令。
在从一组对齐的栅格创建特定因子的概览时,有可能概览不会对齐。请访问 http://trac.osgeo.org/postgis/ticket/1764 查看一个示例,其中概览未对齐。 |
使用加载器创建输入文件并将其以 100x100 块分块上传的示例会话可能如下所示:
# -s use srid 4326 # -I create spatial index # -C use standard raster constraints # -M vacuum analyze after load # *.tif load all these files # -F include a filename column in the raster table # -t tile the output 100x100 # public.demelevation load into this table raster2pgsql -s 4326 -I -C -M -F -t 100x100 *.tif public.demelevation > elev.sql # -d connect to this database # -f read this file after connecting psql -d gisdb -f elev.sql
如果您没有将架构指定为目标表名称的一部分,则该表将在您所连接的数据库或用户的默认架构中创建。 |
使用 UNIX 管道可以一步完成转换和上传:
raster2pgsql -s 4326 -I -C -M *.tif -F -t 100x100 public.demelevation | psql -d gisdb
将马萨诸塞州平面米制航空瓦片加载到名为aerial
的架构中,并创建一个全视图,2级和4级概览表,使用复制模式进行插入(没有中间文件,直接到数据库),并且使用“-e”选项来避免强制将所有内容放入一个事务中(如果你希望立即查看表中的数据而不必等待的话)。将栅格分割成128x128像素的瓦片,并应用栅格约束。同时,包括一个名为“filename”的字段,用于存储瓦片所来自的文件的名称。
raster2pgsql -I -C -e -Y -F -s 26986 -t 128x128 -l 2,4 bostonaerials2008/*.jpg aerials.boston | psql -U postgres -d gisdb -h localhost -p 5432
--get a list of raster types supported: raster2pgsql -G
-G 指令输出类似的列表
Available GDAL raster formats: Virtual Raster GeoTIFF National Imagery Transmission Format Raster Product Format TOC format ECRG TOC format Erdas Imagine Images (.img) CEOS SAR Image CEOS Image ... Arc/Info Export E00 GRID ZMap Plus Grid NOAA NGS Geoid Height Grids
-?
显示帮助屏幕。 如果您不传入任何参数,也会显示帮助。
-G
打印支持的栅格格式。
-c
创建新表并用栅格填充它,这是默认模式
-a
将栅格附加到现有表。
-d
删除表,创建新表并用栅格填充它
-p
准备模式,只创建表。
-C
应用栅格约束——srid、像素大小等,以确保栅格在raster_columns
视图中正确配准。
-x
禁用设置最大范围约束。 仅当还使用 -C 指令时才适用。
-r
设置规范块约束(空间唯一和详尽的切片)。 仅当还使用 -C 指令时才适用。
-s <SRID>
使用指定的 SRID 分配输出栅格。 如果未提供或为零,则将检查栅格的元数据以确定适当的 SRID。
-b BAND
从栅格中提取的波段索引(从 1 开始)。 对于多个波段索引,用逗号(,)分隔。 如果未指定,则将提取栅格的所有波段。
-t TILE_SIZE
将光栅切割成图块,以便在每个表行插入一个图块。 TILE_SIZE
表示为 WIDTHxHEIGHT 或设置为值“auto”,以允许加载程序使用第一个栅格计算适当的切片大小并将其应用于所有栅格。
-P
填充最右侧和最底部的图块,以保证所有图块具有相同的宽度和高度。
-R, --register
将栅格注册为文件系统 (out-db) 栅格。
仅栅格的元数据和栅格的路径位置存储在数据库中(而不是像素)。
-l OVERVIEW_FACTOR
创建栅格的概览。 对于多个因素,用逗号(,)分隔。 概览表名称遵循 o_overview Factor
_table
模式,其中概览因子
是数字概览因子的占位符,表
将替换为基表名称。 创建的概述存储在数据库中,不受-R影响。 请注意,生成的 sql 文件将包含主表和概览表。
-N NODATA
NODATA 值用于没有 NODATA 值的带。
-f COLUMN
指定目标栅格列的名称,默认为“rast”
-F
添加包含文件名的列
-n COLUMN
指定文件名列的名称。 意味着-F。
-q
将 PostgreSQL 标识符括在引号中。
-I
在栅格列上创建 GiST 索引。
-M
真空分析栅格表。
-k
保留空的瓦片并跳过每个光栅波段的NODATA值检查。请注意,这样可以节省检查的时间,但可能会导致数据库中出现更多的垃圾行,并且这些垃圾行不会标记为空的瓦片。
-T tablespace
指定新表的表空间。 请注意,索引(包括主键)仍将使用默认表空间,除非还使用了 -X 标志。
-X tablespace
指定表的新索引的表空间。 如果使用 -I 标志,这适用于主键和空间索引。
-Y max_rows_per_copy=50
使用复制语句而不是插入语句。 可以选择指定 max_rows_per_copy
; 未指定时默认为 50。
-e
单独执行每条语句,不使用事务。
-E ENDIAN
控制生成的光栅二进制输出的字节顺序; 为 XDR 指定 0,为 NDR 指定 1(默认); 现在仅支持 NDR 输出
-V version
指定输出格式的版本。 默认为0。目前仅支持0。
在许多情况下,您需要直接在数据库中创建栅格和栅格表。 有很多函数可以做到这一点。 要遵循的一般步骤。
创建一个包含栅格列的表来保存新的栅格记录,可以通过以下方式完成:
CREATE TABLE myrasters(rid serial primary key, rast raster);
有许多功能可以帮助实现这一目标。 如果您创建的栅格不是其他栅格的衍生品,则需要从以下位置开始:ST_MakeEmptyRaster,然后是 ST_AddBand
您还可以从几何图形创建栅格。 为了实现这一点,您可能需要使用 ST_AsRaster 以及其他函数,例如 ST_Union 或 ST_MapAlgebraFct或任何其他地图代数函数系列。
甚至还有更多选项可用于从现有表创建新栅格表。 例如,您可以使用 ST_Transform在与现有投影不同的投影中创建栅格表
最初填充表后,您将需要在栅格列上创建一个空间索引,如下所示:
CREATE INDEX myrasters_rast_st_convexhull_idx ON myrasters USING gist( ST_ConvexHull(rast) );
请注意 ST_ConvexHull的使用,因为大多数栅格运算符都基于栅格的凸包。
PostGIS 栅格 2.0 之前的版本基于最小外接矩形而不是凸包。 为了使空间索引正常工作,您需要删除它们并替换为基于凸包的索引。 |
使用 AddRasterConstraints应用栅格约束
raster2pgsql
工具使用 GDAL 访问栅格数据,并且可以利用 GDAL 的一个关键功能:能够从远程存储在云“对象存储”(例如 AWS S3、Google Cloud Storage)中的栅格中读取数据。
有效使用云存储栅格需要使用“云优化”格式。 最知名和最广泛使用的是“云优化的 GeoTIFF”格式。 使用非云格式(例如 JPEG 或未平铺的 TIFF)将导致性能非常差,因为系统每次需要访问子集时都必须下载整个栅格。
首先,将栅格加载到您选择的云存储中。 一旦加载,您将有一个 URI 来访问它,可以是“http”URI,有时也可以是特定于服务的 URI。 (例如,“s3://bucket/object”)。 要访问非公共存储桶,您需要提供 GDAL 配置选项来验证您的连接。 请注意,此命令是从云栅格读取并写入数据库。
AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx \ AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ raster2pgsql \ -s 990000 \ -t 256x256 \ -I \ -R \ /vsis3/your.bucket.com/your_file.tif \ your_table \ | psql your_db
加载表后,您需要通过设置两个权限(postgis.enable_outdb_rasters 和postgis.gdal_enabled_drivers)来授予数据库从远程栅格读取的权限。
SET postgis.enable_outdb_rasters = true; SET postgis.gdal_enabled_drivers TO 'ENABLE_ALL';
为了使更改生效并持久化,直接在您的数据库上进行设置。您将需要重新连接以体验新的设置。
ALTER DATABASE your_db SET postgis.enable_outdb_rasters = true; ALTER DATABASE your_db SET postgis.gdal_enabled_drivers TO 'ENABLE_ALL';
对于非公开的栅格数据,你可能需要提供访问密钥来从云端栅格数据中读取。你可以将写入 raster2pgsql
调用时使用的相同密钥设置为在数据库内部使用,使用 postgis.gdal_vsi_options 配置。请注意,可以通过用空格分隔 key=value
对来设置多个选项。
SET postgis.gdal_vsi_options = 'AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
加载数据并设置权限后,您可以使用相同的功能像任何其他栅格表一样与栅格表进行交互。 当需要读取像素数据时,数据库将处理连接到云数据的所有机制。
PostGIS 附带了两个栅格目录视图。 两个视图都利用嵌入在栅格表约束中的信息。 因此,由于强制实施了约束,目录视图始终与表中的栅格数据一致。
raster_columns
此视图对数据库中的所有栅格表列进行编目。
raster_overviews
此视图对数据库中的所有栅格表列进行编目,这些列用作更细粒度表的概述。 当您在加载期间使用 -l
开关时,会生成这种类型的表。
raster_columns
是数据库中所有栅格类型的栅格表列的目录。 它是一种利用表约束的视图,因此即使您从另一个数据库的备份恢复一个栅格表,信息也始终保持一致。 raster_columns
目录中存在以下列。
如果您未使用加载器创建表或忘记在加载期间指定 -C
标志,则可以在事后使用 AddRasterConstraints强制执行约束,以便 raster_columns
目录注册有关栅格切片的通用信息。
r_table_catalog
表所在的数据库。这将始终读取当前数据库。
r_table_schema
栅格表所属的数据库模式。
r_table_name
栅格表
r_raster_column
在r_table_name
表中栅格类型的列。 PostGIS 中没有任何内容可以阻止您在每个表中拥有多个栅格列,因此可以多次列出一个栅格表,并且每个表具有不同的栅格列。
srid
栅格的空间参考标识符。 应该是Section 4.5, “空间参考系统”中的条目。
scale_x
几何空间坐标与像素之间的缩放比例。 仅当栅格列中的所有切片具有相同的scale_x
并且应用此约束时,此功能才可用。 有关更多详细信息,请参阅 ST_ScaleX。
scale_y
几何空间坐标与像素之间的缩放比例。 仅当栅格列中的所有切片具有相同的scale_y
并且应用了scale_y
约束时,此功能才可用。 有关详细信息,请参阅 ST_ScaleY。
blocksize_x
每个栅格图块的宽度(跨像素数)。 有关更多详细信息,请参阅ST_Width。
blocksize_y
每个栅格图块的宽度(向下的像素数)。 有关更多详细信息,请参阅ST_Height。
same_alignment
一个布尔值,如果所有栅格图块具有相同的对齐方式,则该值为 true。 有关更多详细信息,请参阅ST_SameAlignment。
Regular_blocking
如果栅格列具有空间唯一性和覆盖范围切片约束,则该值为 TRUE。 否则,它将是 FALSE。
num_bands
栅格集中每个切片中的波段数。 这与 ST_NumBands 提供的信息相同 ST_NumBands
Pixel_types
定义每个波段的像素类型的数组。 该数组中的元素数量与波段的数量相同。 Pixel_types 是 ST_BandPixelType 中定义的以下类型之一。
nodata_values
双精度数字数组,表示每个波段的 nodata_value
。 该数组中的元素数量与带的数量相同。 这些数字定义了大多数操作中应忽略的每个波段的像素值。 这与ST_BandNoDataValue 提供的信息类似。
out_db
布尔标志数组,指示栅格波段数据是否在数据库外部维护。 该数组中的元素数量与带的数量相同。
extent
这是栅格集中所有栅格行的范围。 如果您计划加载更多数据来更改集的范围,则需要在加载之前运行 DropRasterConstraints 函数,然后在加载后使用AddRasterConstraints 重新应用约束。
Spatial_index
如果栅格列具有空间索引,则为 true 的布尔值。
raster_overviews
目录有关用于概览的栅格表列的信息以及在使用概览时了解的有用的附加信息。 概览表在 raster_columns
和 raster_overviews
中进行编目,因为它们本身就是栅格,但还具有作为高分辨率表的较低分辨率的漫画化图像的额外特殊用途。 当您在栅格加载中使用 -l
开关时,它们会与主栅格表一起生成,或者可以使用 AddOverviewConstraints手动生成。
概览表包含与其他栅格表相同的约束以及特定于概览的附加信息约束。
|
进行概览的两个主要原因是:
通常用于快速映射缩小的核心表的低分辨率表示。
它们的计算速度通常比其更高分辨率的父级更快,因为记录更少,每个像素覆盖更多区域。 尽管计算不如它们支持的高分辨率表那么准确,但它们在许多粗略计算中已经足够了。
raster_overviews
目录包含以下信息。
o_table_catalog
概览表所在的数据库。这将始终读取当前数据库。
o_table_schema
概览栅格表所属的数据库架构。
o_table_name
栅格概览表名称
o_raster_column
概览表中的栅格列。
r_table_catalog
该概览服务所在的栅格表所在的数据库。这将始终读取当前数据库。
r_table_schema
此概览服务所属的栅格表的数据库架构。
r_table_name
此概览服务的栅格表。
r_raster_column
此概览列服务的栅格列。
Overview_factor
- 这是概述表的金字塔级别。 数字越大,表的分辨率越低。 raster2pgsql 如果给定图像文件夹,将计算每个图像文件的概述并单独加载。 假定级别为 1,并且始终为原始文件。 2 级是每个图块代表 4 个原始图块。 例如,如果您有一个包含 5000x5000 像素图像文件的文件夹,您选择将其分块为 125x125,则对于每个图像文件,您的基表将有 (5000*5000)/(125*125) 条记录 = 1600,您的 (l=2) o_2
表将有上限(1600/Power(2,2)) = 400 行,您的 (l=3) o_3
将有上限(1600/Power(2,3) ) = 200 行。 如果您的像素不能被图块的大小整除,您将得到一些废图块(未完全填充的图块)。 请注意,raster2pgsql 生成的每个概览图块与其父级图块具有相同数量的像素,但分辨率较低,其中每个像素代表(原始图块的 Power(2,overview_factor) 像素)。
事实上,PostGIS 栅格为您提供了 SQL 函数来以已知图像格式渲染栅格,这为您提供了很多渲染栅格的选项。 例如,您可以使用 OpenOffice / LibreOffice 进行渲染,如 使用 LibreOffice 基础报告渲染 PostGIS 栅格图形中所示。 此外,您还可以使用本节中演示的多种语言。
在本节中,我们将演示如何使用 PHP PostgreSQL 驱动程序和 ST_AsGDALRaster系列函数将栅格的波段 1、2、3 输出到 PHP 请求流,然后将其嵌入到 img src html 标记中。
示例查询演示了如何将一大堆栅格函数组合在一起,以获取与特定 wgs 84 边界框相交的所有图块,然后将相交图块与 ST_Union联合起来,返回所有波段,使用 ST_Transform转换为用户指定的投影,然后输出 使用 ST_AsPNG将结果显示为 png。
您可以使用
http://mywebserver/test_raster.php?srid=2249
调用以下命令来获取马萨诸塞州平面英尺的栅格图像。
<?php /** contents of test_raster.php **/ $conn_str ='dbname=mydb host=localhost port=5432 user=myuser password=mypwd'; $dbconn = pg_connect($conn_str); header('Content-Type: image/png'); /**If a particular projection was requested use it otherwise use mass state plane meters **/ if (!empty( $_REQUEST['srid'] ) && is_numeric( $_REQUEST['srid']) ){ $input_srid = intval($_REQUEST['srid']); } else { $input_srid = 26986; } /** The set bytea_output may be needed for PostgreSQL 9.0+, but not for 8.4 **/ $sql = "set bytea_output='escape'; SELECT ST_AsPNG(ST_Transform( ST_AddBand(ST_Union(rast,1), ARRAY[ST_Union(rast,2),ST_Union(rast,3)]) ,$input_srid) ) As new_rast FROM aerials.boston WHERE ST_Intersects(rast, ST_Transform(ST_MakeEnvelope(-71.1217, 42.227, -71.1210, 42.218,4326),26986) )"; $result = pg_query($sql); $row = pg_fetch_row($result); pg_free_result($result); if ($row === false) return; echo pg_unescape_bytea($row[0]); ?>
在本节中,我们将演示如何使用 Npgsql PostgreSQL .NET 驱动程序和ST_AsGDALRaster系列函数将栅格的波段 1、2、3 输出到 PHP 请求流,然后将其嵌入到 img src html 标记中。
本练习需要 npgsql .NET PostgreSQL 驱动程序,您可以从 http://npgsql.projects.postgresql.org/ 获取最新的驱动程序。 只需下载最新版本并放入 ASP.NET bin 文件夹中即可开始使用。
示例查询演示了如何将一大堆栅格函数组合在一起,以获取与特定 wgs 84 边界框相交的所有图块,然后将相交图块与 ST_Union联合起来,返回所有波段,使用 ST_Transform转换为用户指定的投影,然后输出 使用 ST_AsPNG将结果显示为 png。
该示例与Section 10.3.1, “PHP 示例使用 ST_AsPNG 与其他栅格函数进行输出”示例相同,只不过是在 C# 中实现的。
您可以使用
http://mywebserver/TestRaster.ashx?srid=2249
调用以下命令来获取马萨诸塞州平面英尺的栅格图像。
-- web.config connection string section -- <connectionStrings> <add name="DSN" connectionString="server=localhost;database=mydb;Port=5432;User Id=myuser;password=mypwd"/> </connectionStrings>
// Code for TestRaster.ashx <%@ WebHandler Language="C#" Class="TestRaster" %> using System; using System.Data; using System.Web; using Npgsql; public class TestRaster : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/png"; context.Response.BinaryWrite(GetResults(context)); } public bool IsReusable { get { return false; } } public byte[] GetResults(HttpContext context) { byte[] result = null; NpgsqlCommand command; string sql = null; int input_srid = 26986; try { using (NpgsqlConnection conn = new NpgsqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DSN"].ConnectionString)) { conn.Open(); if (context.Request["srid"] != null) { input_srid = Convert.ToInt32(context.Request["srid"]); } sql = @"SELECT ST_AsPNG( ST_Transform( ST_AddBand( ST_Union(rast,1), ARRAY[ST_Union(rast,2),ST_Union(rast,3)]) ,:input_srid) ) As new_rast FROM aerials.boston WHERE ST_Intersects(rast, ST_Transform(ST_MakeEnvelope(-71.1217, 42.227, -71.1210, 42.218,4326),26986) )"; command = new NpgsqlCommand(sql, conn); command.Parameters.Add(new NpgsqlParameter("input_srid", input_srid)); result = (byte[]) command.ExecuteScalar(); conn.Close(); } } catch (Exception ex) { result = null; context.Response.Write(ex.Message.Trim()); } return result; } }
这是一个简单的 java 控制台应用程序,它接受一个返回一张图像并输出到指定文件的查询。
您可以从 http://jdbc.postgresql.org/download.html 下载最新的 PostgreSQL JDBC 驱动程序
您可以使用如下命令编译以下代码:
set env CLASSPATH .:..\postgresql-9.0-801.jdbc4.jar javac SaveQueryImage.java jar cfm SaveQueryImage.jar Manifest.txt *.class
并使用类似的命令从命令行调用它
java -jar SaveQueryImage.jar "SELECT ST_AsPNG(ST_AsRaster(ST_Buffer(ST_Point(1,5),10, 'quad_segs=2'),150, 150, '8BUI',100));" "test.png"
-- Manifest.txt -- Class-Path: postgresql-9.0-801.jdbc4.jar Main-Class: SaveQueryImage
// Code for SaveQueryImage.java import java.sql.Connection; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.io.*; public class SaveQueryImage { public static void main(String[] argv) { System.out.println("Checking if Driver is registered with DriverManager."); try { //java.sql.DriverManager.registerDriver (new org.postgresql.Driver()); Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException cnfe) { System.out.println("Couldn't find the driver!"); cnfe.printStackTrace(); System.exit(1); } Connection conn = null; try { conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/mydb","myuser", "mypwd"); conn.setAutoCommit(false); PreparedStatement sGetImg = conn.prepareStatement(argv[0]); ResultSet rs = sGetImg.executeQuery(); FileOutputStream fout; try { rs.next(); /** Output to file name requested by user **/ fout = new FileOutputStream(new File(argv[1]) ); fout.write(rs.getBytes(1)); fout.close(); } catch(Exception e) { System.out.println("Can't create file"); e.printStackTrace(); } rs.close(); sGetImg.close(); conn.close(); } catch (SQLException se) { System.out.println("Couldn't connect: print out a stack trace and exit."); se.printStackTrace(); System.exit(1); } } }
这是一个 plpython 存储函数,它在服务器目录中为每条记录创建一个文件。 需要你安装了 plpython。 应该可以与 plpythonu 和 plpython3u 一起正常工作。
CREATE OR REPLACE FUNCTION write_file (param_bytes bytea, param_filepath text) RETURNS text AS $$ f = open(param_filepath, 'wb+') f.write(param_bytes) return param_filepath $$ LANGUAGE plpythonu;
--write out 5 images to the PostgreSQL server in varying sizes -- note the postgresql daemon account needs to have write access to folder -- this echos back the file names created; SELECT write_file(ST_AsPNG( ST_AsRaster(ST_Buffer(ST_Point(1,5),j*5, 'quad_segs=2'),150*j, 150*j, '8BUI',100)), 'C:/temp/slices'|| j || '.png') FROM generate_series(1,5) As j; write_file --------------------- C:/temp/slices1.png C:/temp/slices2.png C:/temp/slices3.png C:/temp/slices4.png C:/temp/slices5.png
遗憾的是,PSQL 没有易于使用的内置功能来输出二进制文件。 这是一个有点依赖于 PostgreSQL 遗留的大对象支持的 hack。 要使用,首先启动连接到数据库的 psql 命令行。
与 python 方法不同,此方法在本地计算机上创建文件。
SELECT oid, lowrite(lo_open(oid, 131072), png) As num_bytes FROM ( VALUES (lo_create(0), ST_AsPNG( (SELECT rast FROM aerials.boston WHERE rid=1) ) ) ) As v(oid,png); -- you'll get an output something like -- oid | num_bytes ---------+----------- 2630819 | 74860 -- next note the oid and do this replacing the c:/test.png to file path location -- on your local computer \lo_export 2630819 'C:/temp/aerial_samp.png' -- this deletes the file from large object storage on db SELECT lo_unlink(2630819);