引言
遥感影像分类的目标是给每个像元或每个对象赋予一个地物类别标签,输出可以是土地利用图、作物分布图、建筑轮廓或水体范围。它是最经典的遥感应用,也是方法演进最快的一条线:从最大似然到支持向量机,从随机森林到卷积神经网络,再到今天的 Transformer 语义分割。
工程上的难点集中在三处。第一是特征,多光谱只有几个波段,信息量有限,如何用纹理、指数、地形把可分性拉开决定了上限。第二是样本,标注成本高、类别极不平衡,几百个样本常常要覆盖几千平方公里的地物。第三是泛化,模型在训练影像上精度很高,换一景、换一季、换一个区域就大幅下降,这是遥感分类最真实也最容易被忽视的问题。
本文按「任务到方法再到落地」的顺序展开。先厘清分类任务的类型与输出形式,再讲特征工程与经典机器学习,然后进入深度学习语义分割,最后落到精度评价与工程部署。
光谱指数作为分类特征的使用见 植被指数与光谱指数计算 ,标注流程的组织见 计算机视觉数据标注流水线 。云污染会直接污染训练样本,进入建模前必须做云掩膜。
目录
- 分类任务的类型与输出
- 特征工程:光谱、纹理、指数、地形
- 随机森林与梯度提升
- 样本采集与类别不平衡
- 从像素分类到面向对象
- 卷积语义分割:U-Net 与 DeepLab
- Transformer 分割与自监督预训练
- 数据增强与迁移学习
- 精度评价与工程部署
1. 分类任务的类型与输出
先分清几种容易混淆的任务,它们的评价方式与实现差异很大。
| 任务 | 输出 | 典型方法 | 评价指标 |
|---|---|---|---|
| 硬分类 | 每像元一个类别 | 随机森林、SVM | 总体精度、Kappa |
| 软分类 | 每像元各类别概率 | 随机森林概率、Softmax | 对数损失、Brier |
| 亚像元分解 | 每像元各类别丰度 | 线性混合模型 | 丰度 RMSE |
| 目标检测 | 地物框与类别 | Faster R-CNN、YOLO | mAP |
| 语义分割 | 每像元类别图 | U-Net、SegFormer | mIoU、F1 |
| 实例分割 | 每像元类别加实例 | Mask R-CNN | mask mAP |
硬分类与软分类的区别在于是否保留不确定性。工程上推荐先做软分类,把概率图留作后续决策的输入,比如用概率阈值筛出低置信度区域做人工复核,比直接输出硬标签更有价值。
类别体系的设计同样关键。类别数不是越多越好,类别间光谱可分性不足会系统性拉低精度。常见做法是先做 Jeffries-Matusita 距离或类间可分性分析,合并可分性过低的类别,再进入建模。
输出形式还要考虑应用。土地利用变化分析需要时序一致的类别体系,作物识别需要细分到作物类型,而建筑提取可能只需要二分类。任务定义不清会导致后期反复重做标注。
类别体系设计
类别体系要在项目启动时就冻结,中途改动代价极大。设计原则:
- 互斥:一个像元只能属于一个类,类别定义不能重叠。
- 完备:所有地物都有归属,加一个「其他」兜底类,但要警惕它变成垃圾桶。
- 层级化:大类下分子类,如「林地」下分「针叶」「阔叶」,便于按需聚合。
- 可判读:每类都能在影像上被人工识别,否则标注无法执行。
类别体系还要与历史专题图对齐。如果要做长时序变化,新的类别定义必须能映射回旧体系,否则变化检测会引入系统性偏差。
2. 特征工程:光谱、纹理、指数、地形
特征决定了经典方法的上限,也为深度模型提供先验。四类特征各有分工。
光谱特征是原始波段反射率,是基础。但多光谱波段少且相关性强,直接堆叠收益有限。
指数特征把波段组合成物理量,如 NDVI、NDWI、NDBI,能显著提升特定地物的可分性。这类指数在植被、水体、建筑提取中都是关键特征,计算方式与适用条件直接影响分类上限。
纹理特征刻画空间格局,常用灰度共生矩阵 GLCM 的对比度、熵、同质性等。建筑与农田在纹理上差异明显,纹理往往是提升精度的关键。
地形特征来自 DEM,包括高程、坡度、坡向,对区分植被类型与土地利用很有帮助,尤其在山区。
from skimage.feature import graycomatrix, graycoprops
import numpy as np
def glcm_features(patch, levels=32):
q = (patch / (patch.max() + 1e-6) * (levels - 1)).astype("uint8")
m = graycomatrix(q, distances=[1], angles=[0, np.pi/4, np.pi/2], levels=levels)
return np.concatenate([graycoprops(m, p).ravel() for p in ["contrast", "entropy", "homogeneity"]])
特征工程的两条纪律:一是控制特征数量,特征过多会让随机森林的重要性评估失真、让 SVM 过拟合;二是做特征选择,用递归特征消除或基于重要性的筛选,通常能把特征数压到原来的三分之一而几乎不损精度。
标准化也是必需的。不同特征量纲差异大,SVM 与神经网络对尺度敏感,随机森林虽不敏感但统一处理更省心。
特征选择与降维
特征数量增长会带来两个问题:训练变慢,以及噪声特征干扰模型。常用手段:
| 方法 | 原理 | 适用 |
|---|---|---|
| 方差过滤 | 去掉近似常数的特征 | 预处理 |
| 相关性过滤 | 去掉高度相关的冗余特征 | 快速去冗余 |
| 递归特征消除 | 迭代删掉最不重要的特征 | 精度优先 |
| 主成分分析 | 线性降维到正交分量 | 压缩与可视化 |
| 随机森林重要性 | 基于分裂增益排序 | 通用 |
经验上,先用相关性过滤去掉冗余,再用重要性排序保留前 20 到 50 个特征,通常能在几乎不损精度的情况下把训练时间砍半。PCA 会破坏特征的可解释性,在需要解释特征贡献的场景慎用。
3. 随机森林与梯度提升
随机森林是遥感分类最常用的经典方法,原因是它对样本量要求低、对噪声与缺失鲁棒、能输出特征重要性,而且几乎不需要调参。
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(
n_estimators=300, # 树的数量,300 到 500 通常足够
max_features="sqrt", # 每次分裂考虑的特征数,分类常用 sqrt
min_samples_leaf=2, # 叶节点最小样本,防止过拟合
class_weight="balanced", # 处理类别不平衡
n_jobs=-1,
random_state=42,
)
clf.fit(X_train, y_train)
几个调参要点:
- n_estimators 增大到一定程度精度饱和,继续增加只增加耗时,用 OOB 误差曲线找拐点。
- max_depth 通常不限制,靠 min_samples_leaf 控制复杂度。
- class_weight 设为 balanced 能缓解不平衡,但会牺牲多数类精度,需按业务权衡。
梯度提升(XGBoost、LightGBM)在样本量中等、特征丰富时往往比随机森林精度更高,代价是调参更复杂、对异常值更敏感、训练更慢。选择上,如果追求快速基线用随机森林,如果追求精度且有时间调参用 LightGBM。
import lightgbm as lgb
gbm = lgb.LGBMClassifier(
n_estimators=800, learning_rate=0.05, num_leaves=63,
class_weight="balanced", n_jobs=-1,
)
gbm.fit(X_train, y_train, eval_set=[(X_val, y_val)],
callbacks=[lgb.early_stopping(50)]) # 早停防止过拟合
LightGBM 用直方图算法与叶节点优先生长,在同等精度下比 XGBoost 更快、显存更省,适合特征维度高的遥感场景。早停是必备手段,它用验证集监控,在精度不再提升时停止训练,避免过拟合。
两类方法都输出特征重要性,可以反过来指导特征工程:把重要性接近零的特征删掉,重新训练,通常能在几乎不损精度的情况下大幅提速。注意重要性的口径,按分裂次数与按信息增益排序可能不同,报告时要说明用的是哪一种。
4. 样本采集与类别不平衡
样本质量决定一切。遥感分类的样本来源主要有三:野外调查、高分辨率影像目视解译、已有专题图转换。野外调查最准但成本最高,目视解译是主流,专题图转换要注意类别体系与时效的一致性。
样本采集有三条硬纪律:
- 样本要空间均衡,避免全部集中在少数区域,否则模型学到的是区域特征而非类别特征。
- 训练与验证样本要空间独立,随机划分会让相邻像元同时进入训练与验证,导致精度虚高。
- 样本要覆盖类内的光谱变异,同一作物在不同土壤、不同生育期的光谱差异可能超过类间差异。
类别不平衡是常态。耕地、林地可能占九成,而水体、建筑占比很低。常用对策:
| 方法 | 做法 | 代价 |
|---|---|---|
| 重采样 | 欠采样多数类或过采样少数类 | 欠采样丢信息,过采样易过拟合 |
| 类别权重 | 按频次倒数加权 | 多数类精度下降 |
| 合成样本 | SMOTE 插值生成少数类 | 高维空间插值不可靠 |
| 分层采样 | 保证每类样本量接近 | 需额外采集少数类 |
评价时不要只看总体精度。总体精度在不平衡数据上会被多数类主导,一个把所有像元判为耕地的模型也能有九成总体精度。必须同时看每类的召回率与 F1,以及宏平均与加权平均的差异。
样本量没有统一标准,但有经验参考:特征 20 到 50 个、类别 6 到 10 类时,每类 200 到 500 个训练样本通常能得到可用模型,少数类可适当增加。深度模型需要的样本量高一个数量级,每类常需数千个标注像元或数百个影像块。
样本采集还应记录元数据:采集人、日期、影像源、判读依据、置信度。这些元数据在后期复核与争议处理时价值很高,也能用来筛掉低质量样本。
5. 从像素分类到面向对象
像素级分类在高分辨率影像上会遇到「椒盐噪声」:同一地物内部出现零散的错误类别。原因是单个像元的光谱不足以确定类别,而空间上下文被忽略了。
面向对象分类(OBIA)先分割再分类,用分割得到的对象作为分类单元,对象内统计光谱、纹理、形状特征,再用分类器判类。
from skimage.segmentation import slic
segments = slic(image, n_segments=5000, compactness=10, start_label=0) # 超像素分割
分割参数决定结果粒度:n_segments 越大对象越碎,compactness 越大对象越接近方形。分割质量直接决定分类上限,通常要目视调参。
OBIA 的优势是抑制椒盐、能利用形状与上下文特征、对象级结果更接近人工判读习惯。劣势是分割误差会传递到分类,且参数敏感、跨影像迁移差。
深度语义分割在某种意义上取代了 OBIA:卷积网络通过感受野隐式建模上下文,端到端输出平滑的分割图。理解分割网络见 图像语义分割方法 。但在样本极少、算力有限的场景,OBIA 加随机森林仍是可靠且低成本的方案。
OBIA 的标准流程:
- 影像分割,生成对象集合,通常用 SLIC 或分水岭。
- 对象特征提取,统计每个对象的光谱均值、标准差、纹理、形状指数。
- 对象分类,用随机森林或阈值规则给对象赋类。
- 后处理,合并相邻同类对象,去掉过小对象。
形状特征包括面积、周长、紧致度、矩形度,对区分建筑与农田很有用,因为建筑更接近矩形、更紧凑。
6. 卷积语义分割:U-Net 与 DeepLab
U-Net 是遥感语义分割最常用的骨架。编码器逐级下采样提取语义,解码器逐级上采样恢复分辨率,跳跃连接把编码器的细节特征接到解码器,兼顾语义与边界。
import torch
import torch.nn as nn
class DoubleConv(nn.Module):
def __init__(self, cin, cout):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(cin, cout, 3, padding=1), nn.BatchNorm2d(cout), nn.ReLU(inplace=True),
nn.Conv2d(cout, cout, 3, padding=1), nn.BatchNorm2d(cout), nn.ReLU(inplace=True),
)
def forward(self, x):
return self.net(x)
U-Net 的输入通道数等于波段数,可以堆叠多光谱、指数、地形。输出通道数等于类别数,用交叉熵损失训练。
DeepLab 系列用空洞卷积扩大感受野而不损失分辨率,配合 ASPP 多尺度池化,在大范围地物提取上表现更好。它的优势是能捕捉更大范围的上下文,代价是显存占用更高。
几个工程要点:
- 输入切块大小通常取 256 或 512,太大显存吃紧,太小上下文不足。
- 用混合精度训练能显著降低显存并加速,对遥感大图尤其重要。
- 损失函数在不平衡场景用 Dice 与交叉熵的加权组合,Dice 对前景占比低的任务更友好。
- 边界往往是最难的部分,可以在损失里对边界像元加权。
训练数据不足时,先用 ImageNet 或遥感预训练权重初始化编码器,再微调,通常能带来明显提升。
损失函数的选择对不平衡地物很关键:
def combo_loss(pred, target, dice_w=0.5):
ce = nn.functional.cross_entropy(pred, target) # 交叉熵,稳定
prob = pred.softmax(1)
inter = (prob * target).sum()
dice = 1 - (2 * inter + 1) / (prob.sum() + target.sum() + 1) # Dice 对前景占比低更友好
return dice_w * dice + (1 - dice_w) * ce
ASPP 通过不同膨胀率的空洞卷积并行提取多尺度上下文,再把结果拼接。膨胀率通常取 6、12、18,对应不同尺度的地物。对遥感而言,这意味着同一网络能同时照顾小目标与大地物,代价是显存与计算量上升。
7. Transformer 分割与自监督预训练
Transformer 分割把影像切成 patch,用自注意力建模任意两个 patch 之间的关系,天然具备全局上下文。SegFormer 是遥感里较流行的选择,它用分层 Transformer 编码器加轻量 MLP 解码器,结构简单、精度高、推理较快。
Transformer 的优势在超大范围地物与长距离依赖,比如河流连续性的保持、大面积同类地物的内部一致性。劣势是数据需求大、训练成本高。
自监督预训练是缓解数据需求的关键。用海量无标注遥感影像做掩码重建或对比学习,学到通用的表征,再用少量标注微调。
| 预训练方式 | 数据要求 | 典型收益 |
|---|---|---|
| ImageNet 监督 | 自然图像 | 中等 |
| 遥感监督预训练 | 有标注遥感 | 高 |
| 掩码自编码 MAE | 无标注遥感 | 高,泛化好 |
| 对比学习 | 无标注遥感 | 高,需精心设计增强 |
选择上,样本少时优先用现成预训练权重,样本充足时再考虑自监督。注意自然图像与遥感图像的分布差异,直接迁移自然图像权重不如遥感预训练权重。
SegFormer 的结构可以拆成三段理解:先用卷积把影像切成 patch 并嵌入,再用分层 Transformer 编码器在多个尺度上做自注意力,最后用轻量 MLP 解码器把多层特征融合成分割图。相比传统 ViT,它的分层设计让输出保留多尺度信息,更适合密集预测。
自注意力计算量随 patch 数平方增长,因此大图必须切块。切块边界要留重叠,推理时再平均,避免边界处出现断裂。这与卷积滑窗推理的处理方式一致。
8. 数据增强与迁移学习
数据增强是遥感分类性价比最高的技巧。适合遥感的增强有两类。
几何增强:旋转、翻转、缩放、裁剪。遥感影像具有旋转不变性,任意角度旋转都合理,这是与自然图像增强最大的区别,应该充分使用。
光谱增强:亮度抖动、波段加噪、对比度调整。这类增强模拟不同光照与大气条件,能提升跨时相泛化。
import albumentations as A
aug = A.Compose([
A.RandomRotate90(p=0.5),
A.Transpose(p=0.5),
A.RandomBrightnessContrast(p=0.3),
A.GaussNoise(var_limit=(5.0, 20.0), p=0.2),
])
要避免的增强:颜色反转、强色彩抖动会破坏地物的光谱物理意义;弹性形变会让道路、建筑这类刚性结构失真。增强策略要与地物类型匹配。
迁移学习分两个层次:一是用预训练权重初始化,二是冻结编码器只训练解码器。样本极少时冻结训练更稳,样本中等时解冻微调效果更好。学习率上,微调时用较小的学习率,通常比从头训练小一个数量级。
跨区域迁移时要注意光谱差异,比如不同纬度的同一作物物候不同,直接迁移精度会下降。常见做法是目标区域少量样本微调,或在特征层做域适应。
迁移策略可按样本量选择:
| 每类样本量 | 策略 | 说明 |
|---|---|---|
| 小于 50 | 冻结编码器,只训解码器 | 防止过拟合 |
| 50 到 500 | 解冻后几层微调 | 平衡拟合与泛化 |
| 大于 500 | 全网络微调 | 充分利用数据 |
跨传感器迁移时,波段数与波长范围不同,需要先做波段对齐或重采样到公共波段,否则第一层卷积的权重无法复用。
9. 精度评价与工程部署
精度评价是遥感分类最容易被做错的环节。核心是混淆矩阵,以及由它派生的指标。
from sklearn.metrics import confusion_matrix, cohen_kappa_score
cm = confusion_matrix(y_true, y_pred)
kappa = cohen_kappa_score(y_true, y_pred)
oa = (y_true == y_pred).mean() # 总体精度
指标解读:
- 总体精度 OA:正确像元占比,在不平衡数据上会虚高。
- Kappa 系数:扣除随机一致后的精度,对不平衡更稳健,但近年也有争议。
- 每类召回率与精确率:分别对应漏分与错分,业务上关注哪个取决于代价。
- mIoU:各类 IoU 的平均,对少数类更公平,是分割任务的主流指标。
- F1:召回与精确的调和平均,适合二分类地物提取。
验证样本必须空间独立,最好用分层随机采样并按面积加权,否则精度估计会有偏。
部署上有几个关键点。大幅影像无法一次读入,需要滑窗推理再拼接。
def sliding_window_inference(model, image, patch=512, stride=384, n_classes=8):
h, w = image.shape[-2:]
prob = np.zeros((n_classes, h, w), dtype="float32")
count = np.zeros((h, w), dtype="float32")
for y in range(0, h - patch + 1, stride):
for x in range(0, w - patch + 1, stride):
tile = image[..., y:y+patch, x:x+patch]
p = model(tile).softmax(1).numpy()[0]
prob[:, y:y+patch, x:x+patch] += p
count[y:y+patch, x:x+patch] += 1
return (prob / np.maximum(count, 1)).argmax(0) # 重叠区按概率平均,抑制拼接缝
重叠区按概率平均能抑制拼接缝。stride 取 patch 的 0.5 到 0.75 之间是常见折中。
推理结果还要做后处理:去掉小斑块、填洞、平滑边界,必要时用形态学操作。这些步骤与水体提取的后处理同理。发布为可浏览服务时,把结果切成瓦片并分层存储。
线上还要做监控:统计各类面积占比的时序变化,异常跳变往往意味着输入数据或模型出了问题,比如某景影像的波段缺失或云量异常。把分类面积作为监控指标,比只看模型离线精度更能发现真实故障。模型版本要可追溯,每份输出记录训练数据版本、模型权重哈希与推理参数,便于问题复现。
权衡取舍
- 经典方法 vs 深度学习:随机森林样本少也能跑、可解释、训练快;深度模型精度上限高但需样本与算力。
- 像素级 vs 面向对象:像素级简单但对高分辨率影像有椒盐;OBIA 抑制噪声但分割参数敏感。
- U-Net vs Transformer:U-Net 轻量、数据需求小;Transformer 上下文强但训练成本高。
- 增强力度:增强越强泛化越好,但过度增强会破坏光谱物理意义。
- 预训练来源:自然图像权重易得但域差异大,遥感预训练更匹配但获取成本高。
- 精度指标:总体精度直观但会掩盖少数类问题,mIoU 与每类 F1 更公平。
常见坑清单
- 随机划分样本:现象是验证精度虚高,原因是相邻像元同时进入训练与验证,规避方法是空间分块划分。
- 只看总体精度:现象是模型漏掉所有少数类却显示高精度,原因是类别不平衡,规避方法是看每类 F1 与 mIoU。
- 训练与预测的波段顺序不一致:现象是推理结果全错,原因是通道顺序与训练不符,规避方法是固化波段顺序并校验。
- 忘记归一化:现象是深度模型不收敛,原因是输入尺度差异大,规避方法是用训练集统计做标准化。
- 过度颜色增强:现象是模型对真实影像失效,原因是破坏了光谱物理意义,规避方法是只用几何与轻度光谱增强。
- 滑窗 stride 等于 patch:现象是结果出现网格状拼接缝,原因是重叠为零,规避方法是 stride 取 patch 的 0.5 到 0.75。
- 类别体系跨期不一致:现象是时序变化分析出现假变化,原因是类别定义漂移,规避方法是冻结类别体系。
- 用目视解译样本训练又用其验证:现象是精度异常高,原因是样本泄漏,规避方法是验证集独立采集。
- 忽略混合像元:现象是边界地物分类混乱,原因是边界是混合光谱,规避方法是亚像元分解或边界后处理。
- 迁移学习学习率过大:现象是预训练权重被破坏,原因是微调学习率与从头训练相同,规避方法是降低一个数量级。
小结
遥感影像分类的方法演进,本质上是不断引入更多信息的过程:从单像元光谱到纹理、指数、地形,从局部窗口到全局注意力。经典方法胜在样本效率与可解释,深度方法胜在精度上限与上下文建模,二者在真实项目里常常混合使用,比如用深度模型生成初始标签,再用随机森林加人工特征做后处理。
工程成败的关键不在模型结构,而在样本质量、类别体系设计、泛化验证与后处理流水线。把空间独立的验证、每类指标、拼接缝抑制、后处理固化进流程,比换一个更先进的网络更能提升最终可用性。
下一步建议把分类结果接到变化检测上,理解分类后比较法与直接变化检测的差异,见 变化检测与影像时间序列分析 ;也可对照图像语义分割的通用方法补充网络设计的细节。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。