第12章-栅格数据处理

第12章:栅格数据处理

12.1 PostGIS Raster 概述

PostGIS Raster 是 PostGIS 的栅格数据扩展,提供了在 PostgreSQL 数据库中存储和分析栅格数据的能力。

12.1.1 栅格数据特点

┌─────────────────────────────────────────────────────────────┐
│                    栅格数据特点                              │
├─────────────────────────────────────────────────────────────┤
│  组成元素                                                    │
│  ├── 像素(Pixel):最小数据单元                            │
│  ├── 波段(Band):存储不同类型的数据值                      │
│  └── 元数据:空间参考、范围、分辨率等                        │
│                                                             │
│  常见格式                                                    │
│  ├── GeoTIFF (.tif)                                         │
│  ├── JPEG2000 (.jp2)                                        │
│  ├── NetCDF (.nc)                                           │
│  └── HDF (.hdf)                                             │
│                                                             │
│  应用领域                                                    │
│  ├── 卫星影像、航拍影像                                      │
│  ├── 数字高程模型(DEM)                                     │
│  ├── 气象数据、环境数据                                      │
│  └── 土地覆盖、土地利用                                      │
└─────────────────────────────────────────────────────────────┘

12.1.2 启用 PostGIS Raster

-- 创建 raster 扩展
CREATE EXTENSION postgis_raster;

-- 查看版本
SELECT PostGIS_Raster_Version();

-- 查看支持的栅格格式
SELECT * FROM ST_GDALDrivers();

-- 启用外部栅格支持
ALTER SYSTEM SET postgis.enable_outdb_rasters = true;
ALTER SYSTEM SET postgis.gdal_enabled_drivers = 'ENABLE_ALL';
SELECT pg_reload_conf();

12.2 栅格数据导入

12.2.1 使用 raster2pgsql

# 基本导入
raster2pgsql -s 4326 -I -C -M dem.tif public.dem | psql -d gis_db

# 参数说明
# -s 4326    : SRID
# -I         : 创建空间索引
# -C         : 添加约束
# -M         : 使用 COPY 而非 INSERT
# -t 256x256 : 瓦片大小
# -R         : 引用外部文件(不导入数据)
# -r         : 常规块

# 分块导入(推荐用于大文件)
raster2pgsql -s 4326 -I -C -M -t 256x256 large_dem.tif public.dem | psql -d gis_db

# 导入目录下所有文件
raster2pgsql -s 4326 -I -C -M -t 256x256 *.tif public.imagery | psql -d gis_db

# 追加数据
raster2pgsql -s 4326 -a -t 256x256 new_data.tif public.dem | psql -d gis_db

# 外部引用(数据保留在文件系统)
raster2pgsql -s 4326 -R -I -C /path/to/dem.tif public.dem_ref | psql -d gis_db

12.2.2 使用 SQL 导入

-- 从文件创建栅格
SELECT ST_FromGDALRaster(pg_read_binary_file('/tmp/dem.tif'));

-- 创建空栅格
SELECT ST_MakeEmptyRaster(
    100,      -- 宽度(像素)
    100,      -- 高度(像素)
    0,        -- 左上角 X
    100,      -- 左上角 Y
    1,        -- X 像素大小
    -1,       -- Y 像素大小
    0,        -- X 倾斜
    0,        -- Y 倾斜
    4326      -- SRID
);

-- 添加波段
SELECT ST_AddBand(
    ST_MakeEmptyRaster(100, 100, 0, 100, 1, -1, 0, 0, 4326),
    '32BF'::text,  -- 像素类型
    0              -- 初始值
);

12.2.3 像素类型

类型 说明 范围
1BB 1位布尔 0-1
2BUI 2位无符号整数 0-3
4BUI 4位无符号整数 0-15
8BSI 8位有符号整数 -128 到 127
8BUI 8位无符号整数 0-255
16BSI 16位有符号整数 -32768 到 32767
16BUI 16位无符号整数 0-65535
32BSI 32位有符号整数 ±2^31
32BUI 32位无符号整数 0 到 2^32
32BF 32位浮点 单精度浮点
64BF 64位浮点 双精度浮点

12.3 栅格元数据访问

12.3.1 基本元数据

-- 获取栅格宽度和高度
SELECT ST_Width(rast), ST_Height(rast) FROM dem LIMIT 1;

-- 获取波段数量
SELECT ST_NumBands(rast) FROM dem LIMIT 1;

-- 获取像素大小
SELECT ST_PixelWidth(rast), ST_PixelHeight(rast) FROM dem LIMIT 1;

-- 获取 SRID
SELECT ST_SRID(rast) FROM dem LIMIT 1;

-- 获取边界框
SELECT ST_Envelope(rast) FROM dem LIMIT 1;
SELECT Box2D(rast) FROM dem LIMIT 1;

-- 获取完整元数据
SELECT ST_MetaData(rast) FROM dem LIMIT 1;
-- 返回: (upperleftx, upperlefty, width, height, scalex, scaley, skewx, skewy, srid, numbands)

-- 获取波段元数据
SELECT ST_BandMetaData(rast, 1) FROM dem LIMIT 1;

12.3.2 波段属性

-- 获取像素类型
SELECT ST_BandPixelType(rast, 1) FROM dem LIMIT 1;

-- 获取无数据值
SELECT ST_BandNoDataValue(rast, 1) FROM dem LIMIT 1;

-- 获取波段统计
SELECT (ST_SummaryStats(rast, 1)).* FROM dem LIMIT 1;
-- 返回: count, sum, mean, stddev, min, max

-- 获取直方图
SELECT (ST_Histogram(rast, 1, 10)).* FROM dem LIMIT 1;

12.4 像素值操作

12.4.1 读取像素值

-- 读取单个像素值(通过行列号)
SELECT ST_Value(rast, 1, 50, 50) FROM dem LIMIT 1;

-- 读取单个像素值(通过坐标)
SELECT ST_Value(rast, ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)) FROM dem;

-- 读取多个点的值
SELECT 
    p.name,
    ST_Value(d.rast, p.geom) AS elevation
FROM dem d, poi p
WHERE ST_Intersects(d.rast, p.geom);

-- 读取沿线的像素值
SELECT (ST_DumpValues(
    ST_Clip(rast, ST_Buffer(line_geom, 100))
)).* FROM dem;

12.4.2 设置像素值

-- 设置单个像素值
UPDATE dem 
SET rast = ST_SetValue(rast, 1, 50, 50, 100)
WHERE rid = 1;

-- 设置多个像素值
UPDATE dem
SET rast = ST_SetValues(
    rast, 1,
    ARRAY[
        ROW(10, 10, 100)::geomval,
        ROW(11, 10, 101)::geomval,
        ROW(12, 10, 102)::geomval
    ]
)
WHERE rid = 1;

-- 使用几何设置值
UPDATE dem
SET rast = ST_SetValue(rast, 1, polygon_geom, 999)
WHERE ST_Intersects(rast, polygon_geom);

12.4.3 像素值统计

-- 整体统计
SELECT (ST_SummaryStats(rast, 1)).*
FROM dem;

-- 按区域统计
SELECT 
    d.name,
    (ST_SummaryStatsAgg(ST_Clip(r.rast, d.geom), 1, true)).*
FROM dem r, districts d
WHERE ST_Intersects(r.rast, d.geom)
GROUP BY d.name;

-- 获取最大最小值
SELECT 
    MAX((ST_SummaryStats(rast, 1)).max) AS global_max,
    MIN((ST_SummaryStats(rast, 1)).min) AS global_min
FROM dem;

12.5 栅格分析

12.5.1 栅格代数(Map Algebra)

-- 单栅格表达式
SELECT ST_MapAlgebra(rast, 1, '[rast] * 2') FROM dem;

-- 双栅格表达式
SELECT ST_MapAlgebra(
    r1.rast, 1,
    r2.rast, 1,
    '[rast1] + [rast2]'
) 
FROM raster1 r1, raster2 r2
WHERE ST_Intersects(r1.rast, r2.rast);

-- 使用回调函数
CREATE OR REPLACE FUNCTION custom_callback(
    value double precision[][][],
    pos integer[][],
    VARIADIC userargs text[]
)
RETURNS double precision AS $$
BEGIN
    RETURN value[1][1][1] * 2;  -- 简单示例:值乘以2
END;
$$ LANGUAGE plpgsql IMMUTABLE;

SELECT ST_MapAlgebra(
    rast, 1,
    'custom_callback(double precision[], integer[], text[])'::regprocedure,
    '32BF'
) FROM dem;

-- NDVI 计算示例(假设波段4是近红外,波段3是红光)
SELECT ST_MapAlgebra(
    rast, ARRAY[4, 3],
    '([rast.4] - [rast.3]) / ([rast.4] + [rast.3])::float'
) AS ndvi
FROM satellite_imagery;

12.5.2 邻域分析

-- 焦点统计(窗口分析)
-- 计算3x3窗口的平均值
SELECT ST_MapAlgebra(
    rast, 1,
    '32BF',
    'st_mean4ma(double precision[][][], text[], text[])'::regprocedure,
    NULL,
    1, 1  -- 窗口大小:左右各1像素
) FROM dem;

-- 坡度计算
SELECT ST_Slope(rast, 1, '32BF') FROM dem;

-- 坡向计算
SELECT ST_Aspect(rast, 1, '32BF') FROM dem;

-- 山体阴影
SELECT ST_HillShade(rast, 1, '32BF', 315, 45, 1) FROM dem;
-- 参数:栅格,波段,输出类型,方位角,高度角,高程夸张因子

12.5.3 重分类

-- 离散重分类
SELECT ST_Reclass(
    rast, 1,
    '0-100:1, 100-200:2, 200-300:3, 300-:4',  -- 重分类规则
    '8BUI',  -- 输出类型
    0        -- 无数据值
) FROM dem;

-- 连续重分类
SELECT ST_Reclass(
    rast, 1,
    '0-1000:0-100',  -- 线性映射
    '8BUI'
) FROM dem;

-- 创建土地覆盖分类
SELECT ST_Reclass(
    rast, 1,
    '0-10:1, 10-20:2, 20-30:3, 30-40:4, 40-:5',
    '8BUI',
    0
) FROM land_cover;

12.6 栅格裁剪与合并

12.6.1 ST_Clip(裁剪)

-- 使用几何裁剪栅格
SELECT ST_Clip(rast, geom) 
FROM dem, districts
WHERE ST_Intersects(rast, geom) AND districts.name = '东城区';

-- 带无数据值的裁剪
SELECT ST_Clip(rast, geom, -9999, true) FROM dem, districts;

-- 裁剪并保留整个瓦片
SELECT ST_Clip(rast, geom, true) FROM dem, districts;

-- 裁剪多个波段
SELECT ST_Clip(rast, ARRAY[1, 2, 3], geom) FROM multi_band_raster, districts;

12.6.2 ST_Union(合并)

-- 合并栅格
SELECT ST_Union(rast) FROM dem WHERE region = 'north';

-- 使用不同的合并策略
SELECT ST_Union(rast, 'MAX') FROM dem;   -- 取最大值
SELECT ST_Union(rast, 'MIN') FROM dem;   -- 取最小值
SELECT ST_Union(rast, 'MEAN') FROM dem;  -- 取平均值
SELECT ST_Union(rast, 'FIRST') FROM dem; -- 取第一个值
SELECT ST_Union(rast, 'LAST') FROM dem;  -- 取最后一个值
SELECT ST_Union(rast, 'SUM') FROM dem;   -- 求和
SELECT ST_Union(rast, 'COUNT') FROM dem; -- 计数

-- 创建镶嵌影像
CREATE TABLE mosaic AS
SELECT ST_Union(rast, 'MEAN') AS rast
FROM imagery_tiles;

12.6.3 ST_Tile(分块)

-- 将大栅格分割成小瓦片
SELECT ST_Tile(rast, 256, 256) FROM large_raster;

-- 分割并保存
CREATE TABLE dem_tiles AS
SELECT row_number() OVER () AS tid, 
       ST_Tile(rast, 256, 256) AS rast
FROM dem;

12.7 矢量栅格转换

12.7.1 ST_AsRaster(矢量转栅格)

-- 多边形转栅格
SELECT ST_AsRaster(
    geom,
    100,      -- 宽度
    100,      -- 高度
    '8BUI',   -- 像素类型
    1,        -- 值
    0         -- 无数据值
) FROM districts WHERE name = '东城区';

-- 使用参考栅格
SELECT ST_AsRaster(
    geom,
    ref_rast,  -- 参考栅格(用于获取分辨率和范围)
    '8BUI',
    1,
    0
) FROM districts, dem LIMIT 1;

-- 点密度栅格化
SELECT ST_AsRaster(
    ST_Collect(geom),
    0.01,     -- 像素宽度
    0.01,     -- 像素高度
    '16BUI',
    0,
    0
) FROM poi;

12.7.2 ST_Polygon/ST_DumpAsPolygons(栅格转矢量)

-- 栅格转多边形
SELECT ST_Polygon(rast, 1) FROM dem;

-- 分别转换每个值
SELECT (ST_DumpAsPolygons(rast, 1)).* FROM classified_raster;

-- 等值线
SELECT ST_Contour(rast, 1, interval := 100) FROM dem;

-- 提取特定值的区域
SELECT ST_Polygon(ST_Reclass(rast, 1, '500-:1, 0-500:0', '8BUI'), 1)
FROM dem;

12.8 栅格导出

12.8.1 导出为文件

-- 导出为 GeoTIFF
SELECT ST_AsTIFF(rast) FROM dem WHERE rid = 1;

-- 带压缩的导出
SELECT ST_AsTIFF(rast, 'LZW') FROM dem WHERE rid = 1;

-- 导出为 JPEG
SELECT ST_AsJPEG(rast) FROM imagery WHERE rid = 1;

-- 导出为 PNG
SELECT ST_AsPNG(rast) FROM imagery WHERE rid = 1;

-- 使用 GDAL 驱动导出
SELECT ST_AsGDALRaster(rast, 'GTiff', ARRAY['COMPRESS=LZW']) FROM dem;

-- 保存到文件(需要超级用户权限)
COPY (SELECT ST_AsTIFF(ST_Union(rast)) FROM dem) TO '/tmp/output.tif' WITH (FORMAT binary);

12.8.2 导出为其他格式

-- 导出为 WKB
SELECT ST_AsBinary(rast) FROM dem LIMIT 1;

-- 导出为十六进制
SELECT ST_AsHexEWKB(rast) FROM dem LIMIT 1;

-- 获取支持的驱动
SELECT * FROM ST_GDALDrivers() WHERE can_write = true;

12.9 性能优化

12.9.1 分块存储

-- 创建分块表
CREATE TABLE dem_tiled AS
SELECT row_number() OVER () AS rid, 
       ST_Tile(rast, 256, 256) AS rast
FROM dem_original;

-- 创建空间索引
CREATE INDEX idx_dem_tiled_rast ON dem_tiled USING GIST (ST_ConvexHull(rast));

-- 添加约束
SELECT AddRasterConstraints('dem_tiled', 'rast');

12.9.2 外部栅格

-- 引用外部文件(数据不存储在数据库中)
CREATE TABLE dem_outdb AS
SELECT rid, ST_AddBand(
    ST_MakeEmptyRaster(rast),
    '/path/to/dem.tif'::text,
    ARRAY[1]
) AS rast
FROM dem_metadata;

-- 检查是否为外部栅格
SELECT ST_BandIsNoData(rast, 1), ST_BandPath(rast, 1) FROM dem_outdb;

12.10 本章小结

本章详细介绍了 PostGIS Raster:

  1. 基础概念:栅格数据结构、像素类型
  2. 数据导入:raster2pgsql、SQL 方法
  3. 元数据访问:栅格和波段属性
  4. 像素操作:读取、设置、统计
  5. 栅格分析:代数运算、邻域分析、重分类
  6. 裁剪合并:ST_Clip、ST_Union、ST_Tile
  7. 格式转换:矢量栅格互转
  8. 性能优化:分块存储、外部栅格

12.11 下一步

在下一章中,我们将学习拓扑处理,包括:

  • 拓扑数据模型
  • 拓扑构建
  • 拓扑编辑
  • 拓扑验证

相关资源

posted @ 2025-12-29 10:53  我才是银古  阅读(7)  评论(0)    收藏  举报