第16章 - 遥感影像与影像分析
遥感影像在 GeoLibre 里既是”可以看的图”,也是”可以算的数”。这两件事的距离,取决于平台是否把像素值、波段顺序、反射率缩放这些元信息保留到了分析环节。GeoLibre 的做法是把它们全部暴露出来:Style 面板让你自由组合波段与拉伸,Spectral index 与 Raster calculator 让你在像素上做代数,AI Segmentation 与 Object-Based Analysis 把像素聚成对象再分类。
本章基于 GeoLibre 3.4,覆盖影像入口、波段可视化、光谱指数、变化检测、AI 分割、OBIA 全流程与 eCognition 迁移。工具名、参数名、环境变量与字段名全部保留英文原文,来源是 docs/user-guide/segmentation.md、docs/user-guide/obia.md、docs/user-guide/obia-ecognition.md、packages/processing/src/spectral-indices.ts、raster-tools.ts 与 obia.ts。
16.1 影像数据入口
16.1.1 七条入口
| 入口 | 路径 | 提供什么 | 前置条件 |
|---|---|---|---|
| 本地影像 | Add Data → Raster Layer | GeoTIFF / COG 文件 | 无 |
| 远程 COG | Add Data → Raster Layer 填 URL | HTTP Range 按需读块 | 服务端支持 Range + CORS |
| STAC Layer | Add Data → STAC Layer | 任意 STAC 目录的匹配条目 | 目录可达 |
| STAC Catalogs | Plugins → Web Services → STAC Catalogs | STAC Index 全量目录浏览 | 同上 |
| Sentinel-2 Explorer | Plugins → Web Services → Sentinel-2 Explorer | 2015 年至今每一景 Sentinel-2 L2A | 无 API、无服务端 |
| NASA Earthdata | Plugins → Web Services → NASA Earthdata | GIBS 预渲染全球影像图层(1100 多个) | 无 |
| NASA Earthaccess | Plugins → Web Services → NASA Earthaccess | CMR 目录检索 + 下载 granule | Earthdata Login token(下载时) |
| Planetary Computer | Processing → Planetary Computer | Sentinel / Landsat / NAIP / DEM 等 STAC 数据 | 无(服务端签名) |
| Earth Engine | Processing → Earth Engine | GEE 数据集 | 认证 |
再加上两个专业影像入口:Vantor Open Data(灾害事件卫星影像,可按事件前后筛选、可视化 COG、下载)与 Planet Open Data(Planet 灾害数据发布,走 STAC 浏览器)。
16.1.2 Sentinel-2 Explorer:无服务端的数据检索
这个面板值得单独讲,因为它的实现方式很特别:背后没有 API,也没有服务器。
它读的是 Source Cooperative 上的 s2-stac-geoparquet 目录——一份把 Earth Search 索引的每一景都转成 STAC-GeoParquet 的静态数据集。每次检索都是对静态文件的一组 HTTP Range 读,每张影像都从它在 AWS 上的 COG 流式读取。
操作顺序:
- 选 collection:Collection 1(ESA 统一重处理,2015 年 10 月起,默认)或原始 L2A 索引(2016 年 11 月起)。
- 设 From / To 日期。地图会把每个 MGRS 瓦片按该窗口的统计上色,可选四种指标:clearest scene 的云量、scene count(景数)、median cloud(中位云量)、coverage(单景最大填充比例)。绿色好,深红差。
- 用 Max cloud %、Min coverage %、Min scenes per tile 过滤掉不合格的瓦片(变灰)。前两个同时过滤景列表。Show the tile grid 可以只隐藏栅格而不关面板。
- 点一个瓦片检索它的景。面板只读该窗口 GeoParquet 分片里可能包含这个瓦片的行组,通常几百 KB,并会报告读了多少次 Range 请求。
- 景列表可按云量最少、覆盖最多、最新排序;悬停会在图上描出足迹。
- Add scenes as 决定 Add to map 流什么:
| 选项 | 内容 |
|---|---|
| true color(TCI) | 真彩色 |
| 单个波段 | B01–B12、B8A、AOT、WVP、SCL 场景分类;Collection 1 还有云与雪概率掩膜 |
| composite:false color infrared | B08 / B04 / B03 |
| composite:agriculture | B11 / B08 / B02 |
| composite:short-wave infrared | B12 / B8A / B04 |
| index:NDVI | B08 / B04,发散色带 |
| index:NDWI | B03 / B08,发散色带 |
合成与指数都是在浏览器里拼的:每个地图瓦片直接从各波段的 COG 上读对应 overview 的窗口,从 UTM 翘曲过来再绘制——所以 10 m 与 20 m 波段能在全分辨率下合成。反射率已按 04.00 及之后处理基线的 1000 偏移做了校正。
注意:composites 需要 MapLibre 渲染器。主图切到 Cesium 或 ArcGIS 时这几种显示方式不可用。
Download 列出该景的所有文件(TCI、每个波段、SCL、Collection 1 的掩膜),点击会在浏览器(桌面端用系统浏览器)打开 COG 并保存。
16.1.3 三个 “NASA” 不是一回事
这是最容易混的一处:
| 面板 | 数据形态 | 用途 |
|---|---|---|
| NASA Earthdata | GIBS 的预渲染瓦片(1100 多个全球图层,按日期) | 看,不能算。瓦片是 8 位彩色图,没有原始波段 |
| Earthdata GIS | EOSDIS 发布的 ArcGIS image / map / feature 服务 | 看与分析服务端能力 |
| NASA Earthaccess | CMR 目录检索 + 原始 granule 下载 | 拿到可算的原始数据 |
关键区别:只有第三个能给你可计算的像素值。要算 NDVI,必须走 Earthaccess 下载,或者走 Sentinel-2 Explorer / STAC 拿 COG。
Earthaccess 的用法:
- 选热门数据集(ICESat-2 ATL03 / ATL06 / ATL08、GEDI L2A / L2B / L4A、HLS、NASADEM)或按关键词搜索。热门项自动用 Earthdata Cloud 中的最新版本。
- Download 保存 granule 文件(多文件 granule 如 HLS 场景用 Download all,桌面端会问一次目录),Zoom 缩放到它,Details 在 Earthdata Search 里打开。
- 检索不需要账号。下载需要 Earthdata Login token:从 profile 的 Generate Token 页粘贴,或桌面端用用户名密码登录(只保留 token)。token 在桌面端存系统钥匙串,Web 端存浏览器存储。部分数据集还要求先在 Earthdata Login 站点接受一次 EULA。
16.1.4 STAC 的过滤能力
STAC Catalogs 是通用浏览器,任何 STAC API 或静态目录都能连:
- 从 STAC Index 选目录,或粘贴目录 / API URL。静态目录按树浏览,API 走检索。
- 按 collection(多选)、日期范围、区域过滤。区域可以是当前地图范围、手填的 bbox、或在地图上画框。
- STAC API 还接受额外的 JSON 检索参数——这是绕开界面限制、直接用 STAC 原生语法的后门。
提示:三个目录浏览器(STAC Catalogs、Planet Open Data、Portolan)共享面板状态,激活一个会停用另一个。被顶掉的那个如果切换失败会自动回来。
16.2 波段与可视化
16.2.1 波段编号是 1 起
GeoLibre 的所有波段引用都是 1-based,与 GDAL / rasterio 一致,也与栅格计算器里的 A1、A2 对齐。这看起来是小事,但遥感数据描述里常见 0-based 的索引,抄错一位会让整张图变成”看起来像那么回事但颜色完全不对”。
16.2.2 Style 面板里的栅格显示模式
栅格图层的 Style 面板支持三种 mode:
| mode | 用途 | 关键字段 |
|---|---|---|
single |
单波段 + 色带 | 1-based bands、colormap、reversed |
rgb |
三波段合成 | 三个 bands、各自或统一的 rescale |
index |
归一化差值预设 | 指数预设 + 色带 |
公共字段:
| 字段 | 含义 |
|---|---|
rescale |
值域映射区间,形如 [min, max];按波段分别给或统一给 |
nodata |
视为无效的像素值 |
opacity |
图层不透明度 |
gamma |
伽马校正,提升暗部或压暗高光 |
stretch |
拉伸方式:linear / log / sqrt |
colormap / reversed |
色带名与是否反向 |
16.2.3 拉伸:三个选项的适用场景
| stretch | 公式直觉 | 适合 |
|---|---|---|
linear |
线性映射 | 值域均匀分布的数据(反射率、温度) |
log |
压缩高值、展开低值 | 长尾分布(人口、夜间灯光、流量) |
sqrt |
折中 | 影像对比度不足、想同时看清明暗两端 |
拉伸与 rescale 是两件事:rescale 决定”哪一段值域参与映射”(相当于设窗宽窗位),stretch 决定”参与映射后按什么曲线分配”。常见错误是只调 stretch 不调 rescale——曲线换了但值域还是 0–65535,画面上几乎看不出变化。
提示:Sentinel-2 L2A 的原始 DN 值域大致 0–10000(反射率乘 10000)。直接显示会几乎全黑。正确起手是把
rescale设成[0, 3000]左右,再用gamma微调。
16.2.4 三种常见的假彩色
| 目的 | 波段组合(Sentinel-2) | 为什么 |
|---|---|---|
| 植被增强(假彩色红外) | B08 / B04 / B03 | 近红外给红通道,健康植被变鲜红 |
| 农业 | B11 / B08 / B02 | 短波红外对作物含水量敏感 |
| 短波红外 | B12 / B8A / B04 | 地质与烧痕识别 |
这些组合在 Sentinel-2 Explorer 里是预设,在别的数据上要手工在 Style 面板里按 1-based 波段号填。
16.3 光谱指数
16.3.1 八个内置指数
光谱指数不是独立的栅格算法——它是既有栅格计算器的预设前端。spectral-indices.ts 的注释写得很清楚:它把一个指数加一份波段布局编译成同一条单输入波段运算表达式,交给浏览器里的 rasterCalc 或 sidecar 的 raster-calc 脚本求值。
| 指数 id | 面板名称 | 用到的波段 | 公式 | 值域 | 默认色带 |
|---|---|---|---|---|---|
ndvi |
NDVI (vegetation) | red, nir | (nir - red) / (nir + red) |
−1..1 | RdYlGn |
gndvi |
GNDVI (green vegetation) | green, nir | (nir - green) / (nir + green) |
−1..1 | RdYlGn |
ndwi |
NDWI (water, McFeeters) | green, nir | (green - nir) / (green + nir) |
−1..1 | Blues |
ndmi |
NDMI (moisture) | nir, swir1 | (nir - swir1) / (nir + swir1) |
−1..1 | BrBG |
ndbi |
NDBI (built-up) | nir, swir1 | (swir1 - nir) / (swir1 + nir) |
−1..1 | RdBu |
nbr |
NBR (burn ratio) | nir, swir2 | (nir - swir2) / (nir + swir2) |
−1..1 | RdYlGn |
evi |
EVI (enhanced vegetation) | blue, red, nir | 2.5 * ((nir - red) / (nir + 6*red - 7.5*blue + 1)) |
−1..1 | RdYlGn |
savi |
SAVI (soil-adjusted vegetation) | red, nir | ((nir - red) / (nir + red + L)) * (1 + L) |
−1..1 | RdYlGn |
前六个都是”归一化差值”这个统一形状 (a - b) / (a + b),只是分子分母的波段不同。NDBI 的方向与直觉相反:它是 swir1 - nir,所以建成区为正值、植被为负值。
16.3.2 四个传感器预设
波段号是可以手工指定的,但预设覆盖了最常见的情况:
| 传感器 id | 面板名 | 波段布局(1-based) |
|---|---|---|
sentinel2 |
Sentinel-2 (B2, B3, B4, B8, B11, B12) | blue 1、green 2、red 3、nir 4、swir1 5、swir2 6 |
landsat89 |
Landsat 8/9 (B1–B7) | blue 2、green 3、red 4、nir 5、swir1 6、swir2 7 |
naip |
NAIP (R, G, B, NIR) | red 1、green 2、blue 3、nir 4(无 SWIR) |
custom |
Custom | 六个波段号全部手工填 |
注意 Landsat 的 blue 是 2 而不是 1——因为 B1 是海岸气溶胶波段。这是个高频错误:直接按 1 起顺排会让所有指数偏掉。
16.3.3 参数与四条拒绝规则
| 参数 id | 面板标签 | 默认 | 说明 |
|---|---|---|---|
index |
Index | ndvi |
八个指数之一 |
sensor |
Sensor / band layout | sentinel2 |
四个预设之一 |
red / green / blue / nir / swir1 / swir2 |
对应波段号 | — | 仅 sensor 为 custom 时可见 |
L |
Soil factor (L) | 0.5 | 仅 index 为 savi 时可见,0–1 |
scale |
Reflectance scale | 1 | 乘到每个波段 ref 上的系数,必须大于 0 |
四条校验(源码里的抛出条件):
| 情形 | 报错 |
|---|---|
| 未知指数 id | Unknown spectral index: "..." |
| 预设传感器缺这个指数需要的波段 | The ... preset does not include the "..." band this index needs. |
| 波段号不是 ≥ 1 的整数 | Band "..." must be a whole number ≥ 1 (got ...) |
scale ≤ 0 |
Reflectance scale must be greater than 0. |
“预设缺波段”这条在 NAIP 上必然触发:NAIP 只有 R/G/B/NIR,算 NDMI / NDBI / NBR 需要 SWIR——直接用 NAIP 预设会报错。解法是切到 Custom 手工填,或者干脆承认这些指数在 NAIP 上算不出来。
16.3.4 scale 什么时候重要
源码注释把取舍讲透了:
// When scale=1, s*A = A so we emit the bare reference. When scale != 1 we
// wrap every band uniformly — for ratio indices the scale cancels anyway;
// for EVI/SAVI the additive constants require true reflectance values.
return scale === 1 ? `A${band}` : `(${scale} * A${band})`;
翻译成实践规则:
| 指数类型 | 是否需要设 scale |
理由 |
|---|---|---|
| 归一化差值(NDVI / NDWI / NDMI / NDBI / NBR / GNDVI) | 不需要 | 分子分母同乘一个系数,系数约掉了 |
| EVI | 必须 | 公式里的 +1 是反射率意义上的 1,DN 值下完全不成立 |
| SAVI | 必须 | L 是反射率量纲的土壤调节因子 |
Sentinel-2 L2A 的 scale 填 0.0001;Landsat Collection 2 的反射率系数是 0.0000275(加偏移量,需另行处理)。
警告:EVI 不设
scale是最常见的”算出来全是怪值”的原因。DN 值在 0–10000 之间时,分母nir + 6*red - 7.5*blue + 1与分子量级差得离谱,结果会落在几百到几千,而 EVI 的物理范围是 −1 到 1。
16.3.5 Raster calculator
当八个内置指数不够用时,用 Processing → GeoLibre Toolbox → Raster → Raster calculator。它有客户端引擎,浏览器里也能跑。
| 参数 id | 面板标签 | 必填 | 说明 |
|---|---|---|---|
expression |
Expression | 是 | 波段代数表达式 |
b_path |
Raster B (optional) | 否 | 第二张栅格,引用为 B / B1, B2, …;必须与 A 尺寸一致 |
c_path |
Raster C (optional) | 否 | 第三张,引用为 C / C1, C2, …;同样要求尺寸一致 |
表达式语法要点:
- 第一张栅格的波段 1 引用为
A,第 n 个波段引用为An。 - 可用函数:
where、log、exp、sqrt、abs、clip、minimum、maximum、sin、cos、tan。 - 面板描述给的例子就是 NDVI:
(A2 - A1) / (A2 + A1)。
三件事必须自己保证,工具不会替你检查:
- 尺寸一致——B、C 与 A 必须同尺寸,否则直接失败。
- 除零——归一化差值在
a + b = 0处会炸。稳妥写法是用where兜底:where(A1 + A2 == 0, 0, (A2 - A1) / (A2 + A1))。 - NoData 传播——表达式里没有对 NoData 的特殊处理,它会参与运算并污染邻域。
16.3.6 指数选择速查
| 想回答 | 用 | 阈值起点 |
|---|---|---|
| 这里有没有植被 | NDVI | 大于 0.2 视为有植被;大于 0.5 为密植被 |
| 植被长得好不好 | NDVI / EVI | EVI 在高生物量区不易饱和,优于 NDVI |
| 有没有水 | NDWI(McFeeters) | 大于 0 通常为水体;大于 0.3 更稳 |
| 含水量 / 干旱 | NDMI | 负值为缺水 |
| 建成区 | NDBI | 大于 0 倾向建成 |
| 烧痕 | NBR | 火灾前后差值(dNBR)是关键量 |
| 裸土上的植被 | SAVI | L 取 0.5 为通用值 |
注意:阈值不是常数。同一景里阴影水体的 NDWI 可能是负的;大气校正与否会让 NDVI 整体平移 0.05–0.1。任何阈值都应该在当前这景上用样本点验证。
16.4 变化检测与时间序列
16.4.1 双期差分的四步法
变化检测最稳的做法不是”看两张图找不同”,而是把一个指数相减再定阈值:
- 取两期同源影像(同传感器、同处理级别、同季节)。季节不同带来的物候差异会淹没真实变化。
- 各自算指数。用 Spectral index 各跑一次 NDVI。
-
做差。用 Raster calculator,两张图分别放在 A 与 B:
B - A或者带除零保护的归一化差:
where(B + A == 0, 0, (B - A) / (B + A)) -
定阈值并分类。用 Reclassify 把差值映射成类别。
table参数的语法是”最小值:最大值:新值”的规则串,范围左闭右开:min:-0.1:1, -0.1:0.1:0, 0.1:max:2含义:显著减少 = 1、基本不变 = 0、显著增加 = 2。
unmatched参数决定没落进任何区间的值怎么办(nodata设为 NoData,或original保留原值)。
提示:0.1 这个阈值只是起点。NDVI 差值的噪声水平与传感器、大气校正、配准精度都有关。先在同一时期的两景上做一次”伪差分”,量出噪声的量级,再把它当阈值下限。
16.4.2 变化检测的三个前提
| 前提 | 检查方法 | 不满足的后果 |
|---|---|---|
| 几何配准 | 两期影像叠合,看道路/建筑边缘是否对齐 | 未配准会在所有边缘产生”变化”,形成描边状假变化 |
| 辐射一致 | 两期同一稳定地物(深水体、裸岩)的像素值是否接近 | 整体偏移会让阈值法把所有像元判成同一方向变化 |
| 物候一致 | 两期是否同一季节/同一月 | 农田的 NDVI 随生育期剧烈变化,跨季比较毫无意义 |
第三条在农业区是致命的:同一块玉米地在 6 月与 9 月的 NDVI 差 0.5 以上,而这块地一年内什么都没变。
16.4.3 时间序列工具
| 工具 | 在哪 | 做什么 |
|---|---|---|
| Time Slider | Plugins → Time Slider | 通过停靠的时间轴动画化时间序列(COG、XYZ/WMTS、WMS-Time、按时间过滤的 GeoJSON) |
| Layer Swipe | Plugins → Layer Swipe | 用滑动柄并排比较两个图层 |
| Dynamical | Plugins → Web Services → Dynamical | 读 dynamical.org 的 Icechunk/Zarr 档案,按预报批次或时间切片,还能”Time series at a point”出曲线 |
Time Slider 对 COG 的要求是文件名或元数据里带可解析的时间;否则时间轴排不出顺序。
注意:Zarr 图层(含 Dynamical 的)不会随项目恢复——重开项目需要从面板重新加。这是渲染引擎层面的限制,不是面板的疏忽。
16.4.4 时序统计
想量化”某区域 NDVI 的年际趋势”,GeoLibre 没有现成的趋势工具,但有两条可行路径:
路径 A:SQL Workspace。 如果多期指数已经导出成表(每期一列或一行),用 SQL 算线性趋势很简单:
SELECT cell_id,
regr_slope(ndvi, year) AS trend_per_year
FROM ndvi_series
GROUP BY cell_id;
路径 B:Python 控制台。 拿多期栅格做逐像元回归,numpy 一行就够:
import numpy as np
# stack 形状为 (期数, 行, 列)
stack = np.stack(series)
years = np.arange(len(series), dtype=float)
years -= years.mean()
slope = (stack * years[:, None, None]).sum(axis=0) / (years ** 2).sum()
两条路径的分界:已经表格化就用 SQL,还在栅格里就用 Python。
16.5 AI 分割:SamGeo 与 SAM 3
16.5.1 架构:为什么模型不在 sidecar 里
GeoLibre 的 sidecar 是一个轻量 FastAPI 服务。把 PyTorch 加 SAM 3 塞进去会让它变成一个几 GB 的怪物——而且没 GPU 的机器根本跑不动。所以设计是三进程:
SegmentationDialog ──图像+提示──▶ sidecar /ml/segment/* ──▶ samgeo-api (SAM 3) ──▶ GeoJSON
sidecar 只做一个薄反向代理(/ml 前缀)。真正的模型跑在独立的 samgeo-api 服务里,那台机器可以有 GPU,甚至可以是另一台主机。
16.5.2 安装与三个环境变量
在有可用 PyTorch(最好是 CUDA)的 Python 环境里装模型包:
pip install "segment-geospatial[api,samgeo3]"
sidecar 侧只需要它的 HTTP 客户端(模型不在这一侧):
pip install -e "backend/geolibre_server[ml]"
两种启动方式:
自动拉起(默认)。 如果 samgeo-api 在 sidecar 所在环境的 PATH 上,GeoLibre 首次使用时自动启动它。
自己跑 / 跑在另一台机器上。 启动服务并让 GeoLibre 指过去:
samgeo-api --port 8000
# 然后带环境变量启动 sidecar:
GEOLIBRE_ML_SAMGEO_URL=http://127.0.0.1:8000
三个环境变量:
| 变量 | 作用 |
|---|---|
GEOLIBRE_ML_SAMGEO_URL |
已在运行的 samgeo-api 基地址。设了它,sidecar 只代理、不拉起子进程 |
GEOLIBRE_ML_SAMGEO_CMD |
按需启动 samgeo-api 的命令(默认 samgeo-api)。--host / --port 会自动追加 |
GEOLIBRE_ML_DEFAULT_MODEL |
UI 默认模型(默认 sam3) |
注意:桌面版的自动拉起不适用。桌面版把 sidecar 跑在一个受管的 uv 环境里,那个环境带
mlextra 但不带segment-geospatial的模型栈,所以samgeo-api不在它的PATH上。正确做法是:在一个有 PyTorch 的环境里装好并启动samgeo-api,然后从一个已导出GEOLIBRE_ML_SAMGEO_URL的 shell 启动桌面应用:
# 在 PyTorch 环境里
samgeo-api --port 8000
# 带着代理目标启动桌面应用
GEOLIBRE_ML_SAMGEO_URL=http://127.0.0.1:8000 npm run tauri:dev
Tauri 进程会把它自己的环境传给 sidecar。不设这个变量时,sidecar 没有模型后端,/ml/status 会报分割后端不可用。
16.5.3 用 AI Segmentation 对话框
Processing → GeoLibre Toolbox → AI Segmentation。
- 后端不可达时,对话框显示提示与一个 Start server 按钮(桌面端)。点它启动 sidecar 与模型服务。
- Choose a GeoTIFF. 选一个有地理参考的栅格(
.tif/.tiff;PNG/JPG 也能用,但得到的是像素空间结果)。返回的多边形在栅格自己的坐标系里,所以会落在正确位置。 -
选模式:
模式 参数 行为 Text prompt 提示词(如 trees、buildings、cars)+ Confidence threshold(0–1)SAM 3 找出图里每一个匹配对象 Automatic (everything) 无提示词 分割所有可区分对象 Confidence threshold 的方向要记牢:调低找得多,调高更严格。
- 点 Segment。结果加成新的 GeoJSON 多边形图层,图层名取自提示词,地图缩放到它。
16.5.4 四条限制
| 限制 | 说明 |
|---|---|
| 只支持 SAM 3 | GeoLibre 用的是 SAM 3 后端,它覆盖文本、框/点、自动提示。(SAM 2 刻意没接) |
| 仅桌面版 | 和栅格工具一样,分割需要桌面应用与 Python sidecar,纯浏览器构建没有 |
| “No objects found” 是正常结果 | 换个提示词,或降低置信度阈值 |
| 这个对话框只做文本与自动 | 地图上画的框/点提示在交互式 SamGeo 插件里 |
16.5.5 交互式 SamGeo 面板
Plugins → SamGeo 打开一个可停靠面板,它直接和 samgeo-api 说话(默认 http://127.0.0.1:8000,面板里可改),不经过 sidecar——所以它在浏览器构建里也能用。
- 先启动模型服务(
samgeo-api --port 8000),点 Check connection。 - 选影像。Image source 列出地图上所有 COG 或 GeoTIFF 图层,选一个就地分割;或留在 Upload a file 选本地
.tif/.png/.jpg。想快速试手,用 Add Data → Raster Layer 里的 Aerial imagery (UC Berkeley) 样例。 -
选模式:
模式 操作 Text prompt 概念词( building、tree)+ 置信度阈值 + mask 尺寸限制Point prompts 点 + Foreground point / − Background point 后在地图上点;绿色与红色标记显示提示。至少需要一个前景点 Bounding box (find similar) 点 Draw box on map 拖一个矩形;SAM 3 返回所有与框内对象相似的目标 Automatic (everything) 分割所有可区分对象 - 点 Segment。多边形从栅格 CRS 重投影到 WGS84,图层名取自提示词或模式,地图缩放到它。
一个模式上的不对称值得注意:SAM 3 是提示驱动的模型,所以 Automatic 模式实际跑的是 SAM 2 的自动掩膜生成器(checkpoint 在 SAM2 model 里选,points_per_side、IoU 与 stability 阈值在这个模式下生效)。
用 Clear prompts 清除点或框。切换模式会清掉其他模式的提示,关闭面板会移除地图上的提示覆盖层。面板设置(API URL、模式、模型、阈值)随项目保存。
警告:图像会上传到你配置的那个 API URL。项目文件可以带一个保存下来的 API URL,所以用一个别人给的项目去分割本地影像之前,先看清那个字段指向哪里。
16.5.6 sidecar 暴露的端点
| 方法 | 端点 | 说明 |
|---|---|---|
| GET | /ml/status |
后端可用性、默认模型、版本、模型列表 |
| GET | /ml/models |
后端模型目录(可用与已加载) |
| POST | /ml/segment/text |
文本提示分割(prompt、confidence_threshold) |
| POST | /ml/segment/automatic |
自动掩膜生成 |
| POST | /ml/segment/predict |
框/点提示分割(boxes、point_coords、point_labels、point_crs) |
每个 segment/* 端点接受一个 multipart file(图像),外加 model_version(默认 sam3)与 output_format(默认 geojson),返回 GeoJSON FeatureCollection。
16.5.7 不需要 sidecar 的两个
| 工具 | 在哪 | 运行方式 |
|---|---|---|
| Object Detection | Processing → GeoLibre Toolbox → Object Detection | 客户端,onnxruntime-web |
| Segment Everything | Processing → GeoLibre Toolbox → Segment Everything | 客户端,onnxruntime-web |
这两个在浏览器里跑,所以 Web 构建与移动端都能用,不需要 sidecar、不需要 GPU 服务。
16.6 OBIA 全流程
16.6.1 它是什么、在哪
OBIA(Object-Based Image Analysis,面向对象影像分析)的核心主张是:高分辨率影像里一个地物跨很多像素,按像元分类没有意义,应该先把像素聚成对象再分类。
Processing → Object-Based Analysis 打开一个右侧栏工作台(与 Style 面板并排)。它完全在浏览器里跑,用 GeoLibre 自己的 WASM 工具引擎(geolibre-wasm),所以 Web 构建可用。
三个界面细节:
- 首次打开前它不在侧边栏导轨上;打开后导轨图标会切到它;从它的标题栏关闭会把它从导轨上移除。
- 关闭再打开保留当前会话。
- 步骤是顺序的:Segment → Measure → Levels → Label → Classify → Assess → Export。
16.6.2 第一步:Segment
- 先加一个 GeoTIFF 或 COG 栅格图层,再打开工作台。它会自动选第一个栅格图层;换图层用 Image。
- 勾选要参与分割的 Bands。每个波段会先做 z-score 标准化,所以值域大的波段不会压倒其他波段。要用原始多光谱波段(比如红、绿、蓝、近红外),而不是显示用的渲染结果。
- 选 Area:Whole image 或 Current map view。下面那行会说明这次运行读多少像素、在什么分辨率上读。
- 设参数,点 Segment。
| 参数 | 含义 |
|---|---|
| Similarity threshold | 一个像素与其区域种子在标准化波段单位上允许差多少还能并入。值越大,对象越少越大 |
| Minimum object size (pixels) | 小于此值的对象并入最相似的邻居 |
| Seed steps | 以多少组种子分批生长,最同质的先长,所以区域从均匀处往外长而不是从边缘长 |
结果是名为 <image> objects 的矢量图层,每个对象一个多边形,叠在影像上。每个要素的 segment_id 属性(同时是要素 id)就是对象的标号——属性表、选择、后续所有步骤都用同一套对象。
勾选 Also add the label raster to the map 会把标号栅格本身也加进来。
算法是什么:Whitebox 的种子区域生长(image_segmentation)。它不是 eCognition 的多分辨率分割,所以eCognition 的 scale 参数不能照搬——必须在你自己的影像上调阈值与最小尺寸。Whitebox 目录里其他的分割工具(SLIC 超像素、Felzenszwalb 图、标记分水岭)都是同一个区域生长换了阈值映射的包装,这就是工作台用它的真名的原因。
第二个浏览器方法:Felzenszwalb graph method (browser),按 scikit-image 的实现方式做 Felzenszwalb-Huttenlocher 图分割,参数是 Scale、Smoothing (sigma)、Minimum object size,最多读 4 194 304 像素(4096 × 1024)。
原生分割(桌面版):桌面版可以在处理服务里用 scikit-image 做,方法选 SLIC superpixels(Object size (pixels)、Compactness)或 Felzenszwalb graph(Scale、Smoothing (sigma)、Minimum object size (pixels))。原生运行从文件读影像,所以影像必须来自本地 GeoTIFF(URL 加的影像会用浏览器引擎)。上限是 SLIC 1.2 亿像素、Felzenszwalb 2500 万像素。第一次原生运行会往处理服务里装 scikit-image,约一分钟。两种原生方法都是确定性的,重开项目会重建同样的对象。
性能对照(4 波段、9222 × 5089 = 4700 万像素的 Sentinel-2 样例,默认参数):
| 引擎 | 对象数 | Segment | Measure | 峰值内存 |
|---|---|---|---|---|
| 浏览器,区域生长 | 63 942 | 369 s | 208 s | 7.6 GB |
| 原生,SLIC | 94 887 | 46 s | 33 s | 3.9 GB |
| 原生,Felzenszwalb | 234 343 | 131 s | 36 s | 16.9 GB |
注意:浏览器的数字是引擎在浏览器之外跑整景的结果,工作台自己会从 overview 读。
大影像怎么办:单次运行最多读约 1678 万像素(4096 × 4096)。更大的影像仍然能处理:
- Current map view 只读视口内的部分。放大到 Area 那行显示 at full resolution 为止。
- 区域在全分辨率下超限时,工作台改从影像的 overview 读,选能装下的最细 overview(例如 10 m 的 Sentinel-2 会读 20 m)。对象因此更粗,Area 那行会说明。没有 overview 的影像必须先放大,或者先裁(例如 Processing → GeoLibre Toolbox → Raster → Clip by extent)。
- URL 加的 COG 用 HTTP Range 读:列波段只读文件头,运行时只取该区域与该 overview 的瓦片,所以大范围远程场景不会被整份下载。
分割区域与 overview 会随运行一起记录,所以测量、导出、重开项目读的都是同一批像素,Provenance 会列出它们。导出按分割区域的栅格对齐。
从别的软件导入(Import from other software,在 Segment 步骤下面):
| 导入项 | 接受什么 | 行为 |
|---|---|---|
| Objects | 多边形图层 | 把多边形烧到 Segment 里选的影像上作为对象。像素中心落在多边形内即归它。对象 id 来自一个字段(互不相同的正整数,上限 16 777 216),或按顺序编号。没盖住任何像素中心的多边形被丢掉,步骤会说明丢了多少。原始属性保留 |
| Samples | 点图层(或多边形,取内部点) | 给对象打标签,类别来自一个选定字段,角色(training / validation)来自字段或手选。样本冲突时第一个胜出,步骤会说明影响了多少对象 |
| Class list | JSON 的 {"name": ..., "color": "#rrggbb"} 列表,或含 name/color 列的 CSV |
已有类别取文件里的颜色,新类别被添加 |
| Feature table | 含 segment_id 列的 CSV |
并进已测特征(同名替换),所以规则与分类器都能用。匹配不到对象的行被丢弃并计数 |
| Level mapping | child_id,parent_id 的 CSV |
按映射建上层,而不是靠合并。映射漏掉的对象各自成为自己的父对象;一个子对象被指派两个父对象会被拒绝 |
| eCognition rule set | .dcp 规则集或 .dpr 项目 |
转成 Classify 步骤可用的规则集(见 16.7) |
16.6.3 第二步:Measure
对象有了之后,Measure 在原始波段(不是显示渲染)上算逐对象特征,写回对象图层。
| 组 | 字段 |
|---|---|
| Spectral statistics(光谱统计) | 每个参与分割的波段 n:mean_b<n>、std_b<n>、min_b<n>、max_b<n>(n 与源影像波段号一致) |
| Spectral indices(光谱指数) | brightness(各波段均值的平均)、ndvi(红与近红外)、ndwi(McFeeters,绿与近红外)。哪个波段扮演哪个角色可以选;4 波段影像默认红 = 1、绿 = 2、近红外 = 4 |
| Shape(形状) | area_px、perimeter_px、compactness、bbox_width_px、bbox_height_px、elongation |
| GLCM texture(纹理) | 选定波段上的 glcm_contrast_b<n>、glcm_homogeneity_b<n>、glcm_energy_b<n>、glcm_entropy_b<n>。太小的对象凑不出像素对,就没有值 |
| Neighborhood(邻域) | neighbor_count、shared_boundary_total、mean_shared_boundary |
重新测量会替换之前的特征值,但保留其他属性(比如训练标签)。重新分割会开始一批新对象,所以训练分类器之前必须重新测量。
16.6.4 第三步:Levels(层级)
对象可以合并成更粗的层级,像 eCognition 的对象层次:建筑 → 街区 → 片区。
Build coarser level 把当前层的对象并成新层:邻居合并,最相似的先合,直到再合一次会让某对象在标准化波段单位上的值离散度(按面积加权的标准差,跨波段求和)增加超过 scale²。scale 越大,对象越大越杂。
这正是多分辨率分割的颜色准则,只不过作用在整对象上。
两条结构保证:
- 每个粗层对象由下层整对象组成,层级严格嵌套。
- 下层每个对象在
obia_parent里记自己的父对象;粗层每个对象有child_count。
粗层需要在下层测过光谱统计,它的特征从下层推上来:波段统计精确合并自子对象,形状与邻域特征在合并后的对象上重新测(GLCM 纹理不往上带)。粗层在浏览器里建,基于最多 1678 万像素的分割。
上下文特征(Add context features)把每个对象周边的信息加成特征:
| 字段 | 含义 |
|---|---|
nb_contrast_b<n> |
对象波段均值减邻居均值,按共享边界长度加权 |
parent_<feature> |
父对象的波段均值、指数、尺寸、child_count |
parent_is_<class> |
父对象被分到该类时为 1,否则 0(类继承作为特征) |
child_frac_<class> |
对象面积落在下层各类别里的比例(下层分类后才有) |
类名进入字段名时转小写,其他字符换成下划线(”Trees, shrubs” 变成 parent_is_trees_shrubs)。再次添加上下文特征会替换旧的,所以分类完另一层之后要重跑一次。
Work on 决定后续步骤用哪一层:样本、分类器、精度评估、导出都归属那一层,每层各自保存自己的。Apply to other images 用的是第 1 层。 新的分割会开始新的层级;重新测量某一层会丢掉基于它建的层——那些层的对象图层还在图上,不需要就手动删。
16.6.5 第四步:Label samples(标注样本)
- 用 Add class 为每个地表覆盖类型加一个类,命名并选颜色。
- 用 GeoLibre 的任一选择工具选对象:地图选择工具、属性表行、或 Edit → Select by Expression…(例如
[">", ["get", "ndvi"], 0.2]在测量之后选植被对象)。 - 选新标签是 Training 还是 Validation。
- 点某个类行上的标签按钮。对象填上类色,类行统计训练/验证样本数。
| 操作 | 行为 |
|---|---|
| Clear labels of selected | 从选中对象上移除标签 |
| 删除类 | 它的标签一起删 |
| 重命名类 | 它的对象重新打标 |
| Split | 把每类训练样本的一部分(四舍五入,每类至少一个)移到验证集。按类分层、可复现:同一个种子选同一批样本。每次 Split 作用于剩下的训练样本,所以连续 split 会继续搬走一部分 |
标签存在对象自身的 obia_class 与 obia_sample(值为 training 或 validation)属性里,所以随项目保存,属性表里也能看到。
精度评估需要分类器从没训练过的验证样本。要么单独标,要么用 Split 搬一部分。
16.6.6 第五步:Classify
预测结果写进 obia_predicted 属性,图层按预测类着色。四种方式:
| 方式 | 需要样本 | 行为 |
|---|---|---|
| Random forest | 是 | 用勾选的特征(默认全选)在训练样本上训练,验证样本不参与。引擎(classify_objects_random_forest)固定随机种子,所以同输入同输出。缺某个特征值的对象(例如极小对象的 GLCM 纹理)用该特征的均值填充,步骤会说明影响了哪些特征 |
| Threshold rules | 否 | 每条规则把一个特征和一个值比较,对象取从上到下第一条匹配的规则的类。一条都不匹配的落到默认类(灰色显示)。规则要从最具体排到最宽泛 |
| Ruleset | 否 | 跑 eCognition 风格的规则集:模糊类描述 + 过程树,JSON 形式(见下) |
| Inherit from level above | 上层已分类 | 每个对象取父对象的类。先分粗层,再往下继承并细化——例如用上下文特征(parent_is_<class>)做阈值规则:”父对象是水体的建成对象是船” |
Whitebox 目录里的 “SVM” 与 “ensemble” 对象分类器其实是同一个随机森林换了树数,所以工作台只提供随机森林。
提示:随机森林的”缺值用均值填”是一把双刃剑。它在小对象上稳住了训练,但也让这些对象的分类几乎必然落在多数类上。如果 GLCM 特征对你的分类很关键,考虑先按面积过滤掉过小的对象。
16.6.7 规则集(Rulesets)
规则集是一串按顺序跑的过程。每个过程作用于一个 domain:当前类属于 classes 的对象("" 表示未分类;不给 classes 表示任意类),且满足 conditions 里的每一个条件(一个特征、一个操作符 > / >= / < / <= / == / !=、一个值)。
四种过程:
| kind | 作用 |
|---|---|
assign |
把 domain 的对象设为 className |
unassign |
把 domain 的对象变回未分类 |
fuzzy |
按模糊类描述分类。每类用 and(最小值,默认)、or(最大值)或 mean 组合隶属函数;对象取隶属度最高且达到 minMembership(默认 0.1)的类,否则保持不变 |
loop |
重复它自己的过程直到一轮没有变化(或到 maxIterations,默认 100) |
隶属函数的四种形态:
| type | 形状 | 参数 |
|---|---|---|
larger |
在 from 处 0,升到 to 处 1 |
from、to |
smaller |
在 from 处 1,降到 to 处 0 |
from、to |
about |
在 center 处峰值 1,到 width 距离外降为 0 |
center、width |
curve |
过 values(2 到 64 个数,0–1)在 from 到 to 之间等距取点,端点外保持端值 |
values、from、to |
threshold |
条件成立为 1,否则 0 | op、value |
curve 是最重要的一种——eCognition 就是这么存它的隶属函数的,包括 sigmoid。没有隶属函数的类隶属度为 1,与 eCognition 里空类描述的行为一致。
除了已测特征与上下文特征,条件与隶属函数还能读 nb_border_<class>:对象边界里与当前属于该类的邻居共享的比例,每个过程前重算。类必须是图例里的、规则集自己赋的、或(从当前分类开始时)现有分类里有的;拼错的会被拒绝。
后缀规则:类名转小写、去变音符号、连续的空格或标点换成 _(所以 Bare soil 变成 nb_border_bare_soil),两个类名撞到同一个后缀时加 _2、_3。Insert example 会给你的第一个类写一个示例。
有了它,一个 loop 就能一圈一圈把某类往外长。下面这个例子从全体未分类对象开始:
{
"processes": [
{
"kind": "fuzzy",
"name": "spectral classes",
"minMembership": 0.5,
"classes": [
{ "className": "vegetation", "memberships": [{ "field": "ndvi", "type": "larger", "from": 0.1, "to": 0.4 }] },
{ "className": "built", "memberships": [{ "field": "ndvi", "type": "smaller", "from": -0.1, "to": 0.1 }] }
]
},
{
"kind": "loop",
"name": "grow vegetation",
"processes": [
{
"kind": "assign",
"domain": {
"classes": [""],
"conditions": [
{ "field": "nb_border_vegetation", "op": ">=", "value": 0.5 },
{ "field": "ndvi", "op": ">", "value": 0 }
]
},
"className": "vegetation"
}
]
}
]
}
Insert example 会为你的类与特征写出这样的规则集;Open 与 Save 读写文件。规则集边输入边校验,消息会指出第一个问题。勾选 Start from the current classification 可以在现有分类上细化,而不是从未分类开始。跑完每个过程输出一行”改了多少对象”(loop 会说明跑了几轮)。
规则集只读特征与对象图,所以 Apply to other images 可以原样在别的影像上跑。
16.6.8 第六步:Assess accuracy
分类之后,工作台拿预测结果与验证样本(随机森林从没训练过的那批)比对,评分随重新标注实时更新。
| 指标 | 含义 |
|---|---|
| Overall accuracy(总体精度) | 验证对象中预测类与标签一致的比例 |
| Kappa | Cohen’s kappa,扣除随机一致后的一致性 |
| Area-weighted(面积加权) | 每个验证对象按像素面积加权的总体精度。大对象分错比小对象分错更严重。需要形状特征 |
| Confusion matrix(混淆矩阵) | 行是参考类、列是预测类,带每类的 producer’s accuracy(该类被找出了多少)与 user’s accuracy(该类的预测有多可靠) |
Download report (CSV) 保存矩阵与各项数字。
注意:想拿到诚实的分数,验证样本要散布在整个场景,而不是贴着训练样本;而且不要在验证集上反复调参——否则它们就不再独立了。
16.6.9 第七步:Export
对象图层本身就是矢量结果:每个对象的 obia_predicted 属性存着它的类,所以它的图层菜单可以把分类导出成 GeoJSON、GeoPackage、Shapefile 以及其他矢量格式(Processing → GeoLibre Toolbox → Vector → Dissolve 还能按类合并对象)。
Export 步骤还会把类烧到像素栅格上:
| 选项 | 产出 |
|---|---|
| Add classified raster | 按类色渲染的彩色图层 |
| Save class codes (GeoTIFF) | 单波段 Cloud-Optimized GeoTIFF,存类代码,按分割区域的栅格、在源影像的 CRS 里,NoData 为 0 |
| Save legend (CSV) | 类代码、类名、颜色的对照表 |
类代码跟随类别列表顺序(第一个类是 1),所以一个类在多次运行之间保持同一个代码;规则集的默认类如果不在列表里,排在最后。
16.6.10 第八步:Apply to other images
一张影像分类完成后,Apply to other images 把同一套流程跑到项目里的其他栅格图层上:勾选影像,点 Apply。每张影像都按整幅范围分割(超像素上限时用 overview)、用同样的波段与参数、测同样的特征、用当前分类器分类。
| 分类方式 | 行为 |
|---|---|
| Rules | 原样应用 |
| Random forest | 用本影像的训练样本训练,去预测另一张影像的对象——所以其他影像必须有相同顺序的相同波段(同传感器、同处理级别),否则森林看到的值与它学到的不是一回事 |
它用的是点 Apply 那一刻的训练样本,以及最后一次 Classify 用过的特征——所以改过样本之后要重新分类,批处理才会和屏幕上的分类一致。
每张影像得到自己的对象图层,按类着色,步骤下面会列出它的对象数与类别数。标签、精度与导出仍属于第一张影像。
16.6.11 进度、取消与溯源
| 主题 | 行为 |
|---|---|
| 运行时 | 按钮下面那行显示工具名与已用时间 |
| Cancel | 立即停掉正在跑的工具,该步骤保留之前的结果 |
| 批量取消 | 已完成的影像保留 |
| 随项目保存 | 影像与波段选择、参数、类别与分类器设置、每步结果(对象图层保留特征、标签、预测类)、对象层级(每层带自己的样本与分类)、正在工作的层 |
| 粗层标号栅格 | 从下层与 obia_parent 链接重建,不存进项目 |
| Provenance | 展开可见:影像(图层名、文件路径或 URL)、尺寸与所用波段;每一步何时跑、确切的工具调用与参数、geolibre-wasm 与 GeoLibre 版本;每次 hold-out 的比例、种子、搬了多少样本;随机森林的树数、特征数、训练样本数;批量应用时每张影像的工具调用与版本 |
| Copy as JSON | 复制这份记录,就是项目 obia 字段里存的那一份 |
项目不存标号栅格(可能很大)。重开项目后某一步需要它时(重新测量、导出),工作台会在源影像上重跑记录下来的分割——分割是确定性的,而且它会先用保存的分割指纹(对象数 + 每个像素标签的哈希)核对重建结果再使用。如果影像已从项目移除或不再产出同样对象,步骤会明说:重新分割。
注意:Web 应用里从本地文件加的影像不会随项目保存。想重开项目还能重跑各步骤,就按 URL 加影像(或者用桌面版)。
16.7 从 eCognition 迁移
16.7.1 概念映射
工作台读 eCognition 规则集(.dcp)与项目(.dpr)的分类部分,其余靠下表手工翻译,结果用 Import from other software 搬过来。
图例:Yes 行为一致;Partly 可用但有差异;No 不可用。
| eCognition | 工作台 | |
|---|---|---|
| 影像对象层(Image object level) | Levels | Yes |
| 多分辨率分割(第一层) | 种子区域生长、SLIC、Felzenszwalb | Partly:算法不同,scale 参数不能照搬 |
| 多分辨率分割(上层) | Build coarser level | Partly:同样的颜色异质性准则作用在整对象上,best-first;没有形状准则(compactness/smoothness 权重) |
| Chessboard / quadtree 分割 | 无 | No |
| 分割中的主题图层(沿矢量边界切对象) | 无 | No |
| 光谱差异分割 | 小 scale 的 Build coarser level | Partly:按异质性增量合并,不是按均值差 |
| 父对象包含子对象 | 每个粗层都是整子对象的并集(obia_parent、child_count) |
Yes |
| Merge region(按类合并) | 无(合并只按异质性) | No |
| Split / grow / shrink / 对象形态学 | 无 | No |
| 从导出的对象建层 | 先 Import objects,再 Level mapping | Yes |
特征层面的映射:
| eCognition | 工作台字段 | |
|---|---|---|
| Layer mean / std / min / max | mean_b<n>、std_b<n>、min_b<n>、max_b<n> |
Yes |
| Brightness | brightness(波段均值的平均) |
Partly:未加权 |
| 自定义算术特征(指数) | ndvi、ndwi;或导入 feature table |
Partly |
| Area / border length | area_px、perimeter_px(像素与像素边) |
Yes,单位是像素 |
| Compactness / roundness / shape index | compactness(4π·面积/周长²) |
Partly:该族里只有一个形状量 |
| Length/width / asymmetry | elongation(基于外包框)、bbox_width_px、bbox_height_px |
Partly |
| GLCM homogeneity / contrast / entropy | glcm_contrast_b<n> 等 |
Partly:每对象一个对称 GLCM,单波段,距离 1,水平与垂直像素对合并(仅浏览器引擎) |
| Number of neighbors / border to neighbors | neighbor_count、shared_boundary_total、mean_shared_boundary |
Yes |
| 与邻居的均值差 | nb_contrast_b<n>(按边界加权) |
Yes |
| 到某类的相对边界 | nb_border_<class>(规则集里;类名做字段安全后缀) |
Yes |
| 父对象特征 | parent_<feature> |
Yes(波段均值、指数、尺寸) |
| 某类父对象的存在性 | parent_is_<class> |
Yes |
| 子对象特征(数量、某类相对面积) | child_count、child_frac_<class> |
Yes |
| 主题图层特征 | 导入带 segment_id 列的 feature table |
Partly:在工作台之外算,比如在 GIS 里 |
| 到某类的距离 | 无 | No |
16.7.2 导入规则集
在 Import from other software 下,eCognition rule set 读 .dcp 或 .dpr(eCognition / Definiens Developer 7 及以后;加密规则集读不了;文件上限 128 MB):
| eCognition | 转成 |
|---|---|
| Execute child processes | 它的子过程按顺序;重复时变成一个 loop(给定次数,或”while something changes”,最多 1000 轮) |
| Assign class | assign(未分类时 unassign) |
| Remove classification | unassign |
| Classification(类描述) | fuzzy:每个活动类的描述,隶属函数变 curve,阈值变 threshold,按 and(min) 或 or(max) 组合;用类层次的最小隶属度 |
| Image object domain:类过滤 + 用 and 连接的条件 | 过程的 domain |
特征会映射到工作台算同样东西的字段:Mean <layer>、Standard deviation <layer>、Max. pixel value <layer>、Min. pixel value <layer>(按图层的波段)、Brightness、Area(像素)、Number of pixels、Border length(像素)、Rel. border to <class>(→ nb_border_<class>)、Existence of <class> (0)(→ nb_border_<class> 大于 0 的邻居)、Existence of super objects <class> (1)(→ parent_is_<class>,需先加上下文特征)、以及两个图层均值构成的自定义归一化差值(当它读的图层正是 Measure 用的波段时,映射为 ndvi 或 ndwi)。其他特征保留 eCognition 原名——从 eCognition 导一份带该列的 feature table,规则集就能用。
不转换并会列出原因的:分割(在 Segment 里重做)、导出与显示过程、用 or 连接的条件、与变量比较的条件、其他 domain(像素层、链接对象、地图)、最近邻与类描述里的其他算子、变量与数组、合并/生长/收缩对象、层级管理、样本与监督分类,以及任何表里没有的算法。转换出来的过程全都跑在你正在工作的那一层,不管规则集原本写的是哪一层。
16.7.3 转换率有多高
取决于规则集里有多少是分类逻辑。在公开规则集上的统计(容器过程只要有一个子过程转换成功就算转换):
| 规则集 | 过程数 | 转换成功 | 主要没转的 |
|---|---|---|---|
| Buildings and water, Hamden NY | 54 | 39 | merge region |
| Laughing gull nests | 64 | 45 | merge region、层级管理 |
| Water, seed growing | 27 | 14 | 分割、merge region |
| Historical imagery, NAIP | 20 | 7 | 分割、merge region |
| Seafloor geomorphology | 22 | 9 | 分割、对象缩放 |
| NSW estuarine habitats | 240 | 35 | 手工分类、变量、层级 |
| Yalova land cover | 2 813 | 191 | 监督分类、样本、地图 |
| Field boundaries | 292 | 11 | 变量、图层算术、层级 |
这张表最有价值的信息是分布:分类逻辑重的规则集能转 70%,而上千过程的大规则集往往只转 5%–10%——因为大部分过程是分割、层级管理与变量运算,这些工作台没有对应物。
16.7.4 迁移的四步
- 在 eCognition 里跑一遍并导出产物:每层的影像对象(多边形 + id)、样本、类层次(名称与颜色)、你依赖的对象特征(带对象 id 的 CSV)、每层的父对象 id。对象 id 必须是互不相同、不超过 16 777 216 的正整数,更大的要先重编号。
- 在 GeoLibre 里加影像与导出的图层,然后用 Import from other software 依次导入:objects(带 id 字段)、feature table、level mapping、class list、samples。
- 导入规则集(见上),然后重建没转过来的部分:用上表找对应关系,写成规则集或阈值规则。标 No 的算法,保留 eCognition 那部分的结果(把它的对象或类导进来),而不是硬造一个。
- 用 Assess accuracy 对照 eCognition 的结果,验证样本取自 eCognition 的分类。
16.7.5 验证结果:能带过来什么
工作台在三个 eCognition 培训课程的工作流上做过验证,都以 eCognition 自己的分类为参照打分。
数据:Landsat 7 ETM+ 场景(1999 年 9 月),威尔士北部高地,1001 × 1001 像素、15 m:全色波段加六个多光谱波段重采样到它,与 eCognition 项目用的图层和分辨率一致。参照是该项目的 18 类土地覆盖分类(栅格上 24 807 个对象)。
第一个工作流:手工翻译的阈值规则集。 六类阈值规则(按 NDVI 分水与非植被,按波段均值与 NDVI 分森林、改良草地、沼泽/石南,最后兜底一类)。18 个参照类按面积归并成六类后比较:
| 运行 | 面积一致率 | Kappa |
|---|---|---|
| 翻译后的规则集,整景 | 67.2% | 0.55 |
| 翻译后的规则集,留出块 | 66.9% | 0.55 |
| 随机森林,6 类,留出块 | 55%–62% | 0.38–0.49 |
| 随机森林,18 类,留出块 | 30%–37% | 0.24–0.31 |
逐类的 producer/user 精度:水 0.91/0.95、森林 0.82/0.87、沼泽石南 0.69/0.90、非植被 0.78/0.70、改良草地 0.86/0.50。兜底类最弱(0.20/0.24)——课程本身就预期如此。
作为对照,scikit-learn 的随机森林在同特征同标签(全样本)上 out-of-bag 精度是 0.74(6 类)与 0.44(18 类),与工作台的森林在 85% 的对象上一致。结论:限制精度的不是分类器,而是 18 个细类本身、以及标签被搬到画法不同的对象上。
第二个工作流:监督分类。 同一场景另一块 701 × 701 像素区域,参照是 eCognition 的四类分类(森林、水、非植被、其他植被)。工作台用默认阈值的区域生长(10473 个对象)加随机森林(100 棵树):
| 每类样本数 | 随机森林 | Kappa | 1-最近邻 | Kappa |
|---|---|---|---|---|
| 10 | 82%–87% | 0.67–0.75 | 81%–91% | 0.65–0.82 |
| 25 | 82%–84% | 0.67–0.69 | 81%–87% | 0.65–0.74 |
| 100 | 88%–90% | 0.76–0.80 | 86%–88% | 0.74–0.77 |
| 全部(3836 个对象) | 93.5% | 0.86 | 92.6% | 0.84 |
随机森林在同一批样本上与最近邻打平——所以换分类器不是迁移监督工作流的瓶颈,样本数量才是。
第三个工作流:导入的过程树。 一个带主题图层的云标记过程,按 NDVI 分非植被,再在其中按 SWIR 波段均值与 NDVI 分水,然后用 “Rel. border to Water” 把水往外生长十次。导入器只转出了云分类(项目文件里唯一的分类),主题图层的 Num. of overlap: Cloud 特征保留了原名,靠 feature table 供值。两个分割(一个沿云与高地/低地多边形切)没被转换。手势翻译了非植被与水的 assign 过程,以及生长 loop。工作台的 loop 在 3 轮后停下(没有变化了)。merge region 没有对应物,被略过。
| 类 | Producer’s | User’s |
|---|---|---|
| 水 | 0.97 | 0.97 |
| 水(不含生长 loop) | 0.88 | 0.99 |
| 非植被 | 0.74 | 0.82 |
生长 loop 把水体的查全率从 0.88 提到 0.97——原过程树用它来处理小片云下被遮挡的湖面部分。
16.7.6 三条结论
- 推荐流程:区域生长(浏览器里)或 Felzenszwalb / SLIC 分割 → Measure → 导入或翻译 eCognition 的分类规则、检查没转过来的部分、对照 eCognition 输出做精度评估。
- 能带过来的是分类逻辑:阈值、隶属函数、类顺序、domain、基于邻居关系的 loop,都直接翻译且结果相近;随机森林在同一批样本上替代最近邻不掉精度。
- 带不过来的是 eCognition 的分割——没有任何方法能复现它的对象——以及跨层工作的过程。这是迁移时要预期的两处主要差异。
16.8 目标检测与 Segment Everything
| 工具 | 入口 | 引擎 | 输出 |
|---|---|---|---|
| Object Detection | Processing → GeoLibre Toolbox → Object Detection | 客户端 onnxruntime-web |
带类别与置信度的检测框 |
| Segment Everything | Processing → GeoLibre Toolbox → Segment Everything | 客户端 onnxruntime-web |
全图掩膜转多边形 |
| AI Segmentation | Processing → GeoLibre Toolbox → AI Segmentation | sidecar + samgeo-api |
提示驱动的多边形 |
| SamGeo 面板 | Plugins → SamGeo | 直连 samgeo-api |
四种提示模式的多边形 |
三者的分工很清楚:要”图里有什么”用 Object Detection,要”全部分开”用 Segment Everything,要”我要这一类”用 AI Segmentation 或 SamGeo。
前两个跑在浏览器里,所以 Web 与移动端可用,代价是模型小、类别固定;后两个需要 GPU 服务,换来 SAM 3 的开放词汇能力。
16.9 精度与适用边界
16.9.1 精度报告怎么读
| 指标 | 回答 | 什么时候会误导 |
|---|---|---|
| Overall accuracy | 总体对了多少 | 类别极度不平衡时(99% 是森林,全判森林也有 99%) |
| Kappa | 扣除随机一致后的表现 | 类分布极偏时数值偏低,不代表方法差 |
| Producer’s accuracy | 这个类被找出了多少(查全) | 单看它会把”宁可错杀”的方法显得很好 |
| User’s accuracy | 判成这个类的有多可靠(查准) | 单看它会把”宁可漏掉”的方法显得很好 |
| Area-weighted | 按面积加权的总体精度 | 需要形状特征;大对象主导结果 |
必须成对看 producer’s 与 user’s。一个类的 0.95/0.30 意味着”几乎全找到了,但标成它的大多是错的”——这比 0.60/0.60 更糟。
16.9.2 适用边界
| 方法 | 分辨率要求 | 类别数上限(实践) | 样本要求 | 典型失效场景 |
|---|---|---|---|---|
| 光谱指数 + 阈值 | 10–30 m | 2–4 | 无 | 混合像元、薄云、阴影 |
| 随机森林(像元) | 10–30 m | 5–12 | 每类 100+ | 空间自相关导致验证集不独立 |
| OBIA 规则集 | ≤ 10 m | 5–10 | 无(需调参) | 规则之间互相遮蔽 |
| OBIA 随机森林 | ≤ 10 m | 5–12 | 每类 50+ 对象 | 对象边界与地物边界不一致 |
| SAM 3 文本提示 | ≤ 1 m | 概念级 | 无 | 小目标、遮挡严重、非可见光 |
| Object Detection | ≤ 0.5 m | 固定类别集 | 无 | 尺度差异大、旋转目标 |
16.9.3 十个常见错误
| 现象 | 原因 | 修法 |
|---|---|---|
| 算出的 NDVI 全在 −2 到 2 之外 | 波段号错位(Landsat 的 blue 是 2 不是 1) | 核对传感器预设 |
| EVI 值域是几百 | 没设 scale |
填 0.0001(S2)或 0.0000275(Landsat C2) |
| 影像显示几乎全黑 | 没设 rescale |
从 [0, 3000] 起调 |
| NDWI 判水体到处是水 | 阈值套用了别的场景 | 在当前景上用样本点重新定阈值 |
| 变化图全是边缘描边 | 两期影像未配准 | 先配准,或用更粗的聚合单元 |
| OBIA 对象把道路和田地粘在一起 | 相似度阈值太大 | 调小阈值,或减小最小对象尺寸 |
| 分类结果整片是同一类 | 训练样本严重不平衡 | 每类样本数拉平 |
| 精度 95% 但图上明显错 | 验证样本与训练样本空间重叠 | 用 Split 做空间留出 |
| 批量应用后另一张影像结果全错 | 波段顺序或数量不同 | 确认同传感器同处理级别 |
| 粗层对象与子对象对不上 | 重新测量了子层 | 重新建粗层 |
16.9.4 一条元规则
所有基于阈值的结论都需要在当前数据上重新验证。 无论是 NDVI > 0.2 判植被、NDWI > 0 判水体,还是 dNBR 的burn severity 分级,那些数字都来自特定传感器、特定大气条件、特定地区的经验。把它们当”物理常数”用,是遥感分析里最常见的系统性错误。
16.10 本章小结
- 影像入口有七条(本地、远程 COG、STAC Layer、STAC Catalogs、Sentinel-2 Explorer、NASA 三兄弟、Planetary Computer / Earth Engine)。只有能给原始像素值的入口才能做分析——GIBS 的预渲染瓦片不能。
- Sentinel-2 Explorer 背后没有服务端:它读 Source Cooperative 上的静态 STAC-GeoParquet,每次检索是 HTTP Range 读;合成与指数在浏览器里拼,反射率已按 04.00 基线的 1000 偏移校正;composites 需要 MapLibre 渲染器。
- 三个 “NASA” 分工:Earthdata (GIBS) 是预渲染瓦片(只能看)、Earthdata GIS 是 ArcGIS 服务、Earthaccess 才是原始 granule 下载(要 Earthdata Login token)。
- 波段引用一律 1-based。Landsat 8/9 的 blue 是 2(B1 是海岸气溶胶),这是最高频的错位来源。
- Style 面板三种 mode(
single/rgb/index),公共字段包括rescale、nodata、opacity、gamma、stretch(linear/log/sqrt)、colormap。rescale 决定值域,stretch 决定曲线,两者要一起调。 - 八个内置光谱指数都是栅格计算器的预设前端:六个归一化差值、EVI、SAVI。归一化差值不需要设
scale,EVI 与 SAVI 必须设。 - 四个传感器预设:Sentinel-2(blue 1 / red 3 / nir 4)、Landsat 8/9(blue 2 / red 4 / nir 5)、NAIP(无 SWIR,算不了 NDMI/NDBI/NBR)、Custom。
- Raster calculator 的表达式把第一张栅格写作
A(波段 1)与An,可用where/log/exp/sqrt/abs/clip/minimum/maximum/sin/cos/tan。除零要自己用where兜底,尺寸一致性它不替你检查。 - 变化检测的四步是:取同期同源影像 → 各算指数 → 相减 → Reclassify 定阈值(规则串形如
min:-0.1:1, -0.1:0.1:0, 0.1:max:2,区间左闭右开)。三个前提:几何配准、辐射一致、物候一致。 - AI Segmentation 是三进程架构:对话框 → sidecar 的
/ml反向代理 → 独立的samgeo-api。桌面版的 sidecar 环境不带模型栈,所以必须手工起服务并导出GEOLIBRE_ML_SAMGEO_URL。 - SamGeo 面板直连
samgeo-api、在浏览器里也能用;它的 Automatic 模式实际跑的是 SAM 2 的自动掩膜生成器,其余三种模式走 SAM 3。 - OBIA 工作台完全在浏览器里跑(
geolibre-wasm),八步流程:Segment → Measure → Levels → Label → Classify → Assess → Export → Apply。单次分割上限约 1678 万像素(4096 × 4096),超了改读 overview 或只跑当前视口。 - OBIA 的分割不是 eCognition 的多分辨率分割,是 Whitebox 的种子区域生长,scale 参数不能照搬。重新分割要重新测量;重新测量某一层会丢弃基于它建的粗层。
- 关键字段名:
segment_id、obia_class、obia_sample、obia_predicted、obia_parent、child_count,以及特征族的mean_b<n>/nb_contrast_b<n>/parent_is_<class>/nb_border_<class>。 - 规则集四种过程:
assign/unassign/fuzzy/loop;隶属函数五种形态里curve是 eCognition 的原生存储形式。nb_border_<class>让 loop 能一圈一圈把类往外长。 - 精度必须成对读 producer’s 与 user’s,并尽量用面积加权与空间留出的验证样本。
- eCognition 迁移的结论:分类逻辑能带过来,分割带不过来。分类逻辑重的规则集能转 70%,上千过程的大规则集往往只转 5%–10%。
16.11 实践练习
-
波段号实验:取一份 Landsat 8/9 的 7 波段反射率数据,先用 Sentinel-2 的预设(blue 1 / red 3 / nir 4)算一次 NDVI,再用 Landsat 预设算一次。把两个结果叠在同一份真彩色图上对比,说明错误结果在哪些地类上错得最明显。
-
scale 的作用:对同一份 Sentinel-2 L2A 数据,把 Spectral index 设为 EVI,
scale分别填 1 与 0.0001。记录两次输出的最小值/最大值(用图层 Metadata 或 Zonal statistics),并解释为什么其中一个在物理上不成立。 -
变化检测全流程:取同一区域两个年份的 Sentinel-2 NDVI,用 Raster calculator 做差(记得用
where处理除零),再用 Reclassify 分成”减少 / 不变 / 增加”三类。然后做一次伪差分(同一年两景),量出噪声量级,据此论证你的阈值选得是否合理。 -
OBIA 全流程:用 Processing → Object-Based Analysis 对一份高分辨率影像走完 Segment → Measure → Label → Classify → Assess。要求:至少 4 个类、每类至少 20 个训练样本、用 Split 留出验证集、记录 Overall accuracy 与 Kappa,并只报告验证集上的分数。最后导出 Save class codes (GeoTIFF) 与 Save legend (CSV)。
-
规则集练习:用 Insert example 生成一个规则集,改写成”先按 NDVI 分植被与非植被,再用
nb_border_<class>的 loop 把植被往外长 3 轮”,勾选 Start from the current classification 对比开与不开的差别。记录每个过程改了多少对象。 -
精度陷阱识别:构造一个类别极不平衡的场景(例如 95% 是一个类),故意做一个”全判多数类”的分类,算出它的 Overall accuracy、Kappa 与各类的 producer’s/user’s accuracy。用这组数字说明为什么不能只看 Overall accuracy。
16.12 延伸阅读
- 处理工具箱的整体结构与引擎选择器:见 第12章 地理处理工具箱
- 栅格工具与投影对分析的影响:见 第14章 地形与水文分析
- 云原生格式与 COG 的读写:见 第05章 数据添加与格式支持
- 用 SQL 汇总分类面积:见 第11章 SQL 工作区与 DuckDB 空间分析
- 样式、色带与图例的完整说明:见 第07章 样式符号化与图例
- 把影像分析串成可复用流程:见 第13章 模型构建器与自动化工作流