对于大多数用例,您将通过使用打包的 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 像素的瓦片,并应用栅格约束。使用复制模式而不是表插入。(-F) 包含一个名为 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
显示帮助屏幕。如果您没有传入任何参数,也会显示帮助信息。
打印支持的栅格格式。
创建新表并用栅格填充它,这是默认模式
将栅格追加到现有表中。
删除表,创建新表并用栅格填充它
准备模式,只创建表。
应用栅格约束 - srid、像素大小等,以确保栅格在 raster_columns
视图中正确注册。
禁用设置最大范围约束。仅在也使用 -C 标志时应用。
设置用于常规阻塞的约束(空间唯一和覆盖瓦片)。仅在也使用 -C 标志时应用。
为输出栅格分配指定的 SRID。如果未提供或为零,将检查栅格的元数据以确定合适的 SRID。
从栅格中提取的波段的索引(从 1 开始)。对于多个波段索引,用逗号 (,) 分隔。如果未指定,将提取栅格的所有波段。
将栅格切割成瓦片,每个表行插入一个瓦片。 TILE_SIZE
表示为 WIDTHxHEIGHT 或设置为值“auto”,以允许加载器使用第一个栅格计算合适的瓦片大小并应用于所有栅格。
填充最右边和最下面的瓦片,以确保所有瓦片具有相同的宽度和高度。
将栅格注册为文件系统(数据库外)栅格。
仅将栅格的元数据和指向栅格的路径位置存储在数据库中(而不是像素)。
-l
OVERVIEW_FACTOR
创建栅格的概览。对于多个因子,用逗号 (,) 分隔。概览表名遵循模式 o_overview factor
_table
,其中 overview factor
是数值概览因子的占位符,table
被替换为基本表名。创建的概览存储在数据库中,不受 -R 影响。请注意,您生成的 sql 文件将包含主表和概览表。
NODATA
在没有 NODATA 值的波段上使用的 NODATA 值。
指定目标栅格列的名称,默认值为“rast”。
添加一个包含文件名的列。
指定文件名列的名称。隐含 -F。
将 PostgreSQL 标识符括在引号中。
在栅格列上创建 GiST 索引。
对栅格表进行真空分析。
保留空瓦片,并跳过每个栅格波段的 NODATA 值检查。请注意,您可以节省检查时间,但最终可能会在数据库中留下更多垃圾行,这些垃圾行不会被标记为空瓦片。
tablespace
指定新表的表空间。请注意,除非还使用 -X 标志,否则索引(包括主键)将继续使用默认表空间。
tablespace
指定表的新索引的表空间。这适用于主键和空间索引(如果使用了 -I 标志)。
max_rows_per_copy=50
使用 copy 语句而不是 insert 语句。可以选择指定 max_rows_per_copy
;未指定时默认为 50。
单独执行每个语句,不要使用事务。
控制生成的栅格二进制输出的字节序;指定 0 表示 XDR,指定 1 表示 NDR(默认);目前仅支持 NDR 输出。
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
栅格的空间参考标识符。应为 第 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 提供的信息相同。
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
表将有 ceiling(1600/Power(2,2)) = 400 行,您的 (l=3) o_3
将有 ceiling(1600/Power(2,3) ) = 200 行。如果您的像素不能被图块大小整除,您将得到一些废弃的图块(未完全填充的图块)。请注意,raster2pgsql 生成的每个概览图块都具有与其父图块相同数量的像素,但解析度较低,其中每个像素代表原始文件的 (Power(2,overview_factor) 个像素。
PostGIS Raster 提供了 SQL 函数来渲染已知图像格式的栅格,这为您提供了许多渲染选项。例如,您可以使用 OpenOffice/LibreOffice 进行渲染,如 使用 LibreOffice Base Reports 渲染 PostGIS Raster 图形 中所示。此外,您还可以使用本节中所示的多种语言。
在本节中,我们将演示如何使用 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。
此示例与 第 9.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 控制台应用程序,它接受一个返回一个图像的查询,并将结果输出到指定的文件。
您可以从 https://jdbc.postgresql.ac.cn/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 遗留的大对象支持的小技巧。要使用它,首先启动连接到数据库的 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);