高光谱数据集下载与预处理实战:从Indian Pines到GF-5的完整流程
1. 高光谱数据集到底解决什么问题高光谱遥感这几年从实验室走向工程化的速度明显加快尤其是农业估产、矿物填图、水质监测、伪装识别这几个方向几乎每个项目立项后的第一件事就是找数据。但真正上手的人都知道公开数据集虽然不少可散落在各个课题组主页、会议附件、网盘链接里有的链接早就失效有的下载下来发现波段顺序对不上还有的连标签文件都缺。我前后做过三个高光谱分类项目光是整理可用的数据集就花了将近两周踩过的坑足够写一篇避坑指南。这篇文章要做的就是把目前主流且验证可用的高光谱数据集做一次系统梳理同时把下载之后怎么用、怎么转反射率、怎么切patch、怎么接分类网络这些实操环节讲透。适合刚进入遥感方向的研究生、做地物分类的算法工程师以及需要快速验证想法的应用开发者。不管你是用MATLAB还是Python是做传统机器学习还是深度学习这里面的内容都能直接抄作业。提示本文提到的所有数据集均为公开学术资源下载后请遵守各自的使用协议引用对应论文。2. 主流高光谱数据集全景梳理2.1 经典基准数据集从Indian Pines到Salinas高光谱分类领域有几个“老牌”数据集几乎每篇论文都会拿它们做对比实验。Indian Pines是最早的一批1992年用AVIRIS传感器在美国印第安纳州一片农业区采集空间分辨率20米波段数220个去掉吸水波段后剩200个地物类别16类主要是玉米、大豆、小麦等农作物。这个数据集的特点是类别极不平衡有些类只有几十个样本训练时容易过拟合所以很多论文会做样本增强或者用注意力机制来缓解。Salinas是同一传感器在加州Salinas Valley采集的空间分辨率3.7米波段数224个去掉坏波段后204个类别也是16类但样本分布比Indian Pines均衡得多蔬菜、葡萄园、裸土这些类别的区分度更高。Pavia University用的是ROSIS传感器意大利帕维亚大学城区域空间分辨率1.3米波段数115个去掉噪声波段后103个9类地物包括沥青、草地、树木、金属板等。这个数据集的空间细节更丰富适合做空谱联合分类。这三个数据集在IEEE DataPort和Purdue大学的实验室主页上都有稳定下载链接格式一般是.mat文件里面包含数据立方体和对应的ground truth标签矩阵。下载后直接用scipy.io.loadmat读取即可注意有些版本的数据立方体是uint16需要转成float再做归一化。2.2 国产高光谱数据GF-5与珠海一号国产卫星数据这两年的可用性提升很快。GF-5搭载的AHSI传感器有330个波段光谱范围覆盖400到2500纳米空间分辨率30米幅宽60公里。做蚀变信息提取时GF-5的短波红外波段对羟基和碳酸盐矿物的识别效果很好在ENVI里用光谱角制图或者匹配滤波就能出初步结果。下载渠道一般通过中国资源卫星应用中心申请部分样例数据在开放平台上可以直接获取。珠海一号高光谱星座由多颗卫星组成空间分辨率10米波段数32个虽然波段数比GF-5少但重访周期短适合做时间序列分析。它的数据格式是GeoTIFF每个波段一个文件用GDAL或者rasterio读取后堆叠成三维数组。需要注意的是珠海一号的辐射定标系数在元数据文件里转反射率之前必须做辐射定标否则不同时相的数据没法直接比较。2.3 深度学习专用数据集ICVL与HarvardICVL数据集原本是做光谱重建用的包含201个场景的高光谱图像波段数31个波长范围400到700纳米空间分辨率1392乘1300。后来很多人拿它做分类和超分辨率的预训练。这个数据集在ICVL项目主页上提供下载格式是.mat每个文件包含一个reflectance立方体。转反射率的时候要注意ICVL已经做过辐射定标直接除以白板参考就行。Harvard数据集包含50个场景波段数31个波长范围420到720纳米空间分辨率1392乘1040。它的特点是场景多样有室内、室外、人脸、纸张等适合做跨域迁移学习。下载后需要自己切patch一般取32乘32或者64乘64重叠率设一半这样能保证样本量足够。2.4 数据集对比速查表数据集传感器波段数空间分辨率类别数适用任务Indian PinesAVIRIS20020m16分类、降维SalinasAVIRIS2043.7m16分类、空谱联合Pavia UniversityROSIS1031.3m9分类、目标检测GF-5AHSI33030m按需蚀变提取、水质珠海一号OHS3210m按需时间序列、农业ICVLSpecim311392x1300无光谱重建、预训练HarvardSpecim311392x1040无迁移学习、重建这张表建议存下来选数据集的时候先看任务类型和空间分辨率是否匹配。做精细农业分类Pavia University和Salinas更合适做大范围矿物填图GF-5的波段覆盖更有优势做光谱重建预训练ICVL和Harvard的样本量足够。3. 下载之后怎么用从原始文件到可训练数据3.1 数据读取与格式转换下载下来的文件格式主要有三种.mat、GeoTIFF和ENVI标准格式。.mat用Python读取最方便一行代码就能加载import scipy.io as sio data sio.loadmat(Indian_pines_corrected.mat) cube data[indian_pines_corrected] # 形状 (145, 145, 200) gt sio.loadmat(Indian_pines_gt.mat)[indian_pines_gt]GeoTIFF用rasterio读取注意波段顺序。有些国产数据是BSQ格式存储读取后需要转成BIP或者BIL否则按像素取光谱曲线时会出错。ENVI格式用spectral库读取header文件里的interleave字段决定了内存布局data ignore value字段标记了无效像元这些细节不注意的话后面做归一化会把背景值也算进去。注意读取后先检查数据范围。如果最大值是65535说明是uint16需要除以65535转成0到1如果最大值是1附近说明已经归一化过不要再除。3.2 辐射定标与反射率转换高光谱转反射率是绕不开的一步。原始DN值受太阳高度角、大气条件、传感器增益影响直接拿来做分类不同时相的数据分布会漂移。标准流程是辐射定标得到辐亮度再大气校正得到反射率。ENVI里的FLAASH模块可以做大气校正但参数多新手容易卡在气溶胶模型选择上。如果只是做算法验证可以用简化方法找一块已知反射率的白板区域计算白板像元的平均DN值然后整幅影像除以这个值。公式是reflectance DN / mean(white_panel_DN)这个方法在ICVL和Harvard上够用因为采集时已经放了白板。但GF-5和珠海一号的数据必须走完整的大气校正流程否则短波红外波段的反射率会偏高影响矿物指数计算。3.3 切patch与样本增强深度学习模型需要固定尺寸的输入所以要把大图切成小patch。常用尺寸是32乘32或64乘64步长设成patch尺寸的一半这样能保证边缘样本也被覆盖到。切之前先做PCA降维把200个波段降到30个左右既能保留主要信息又能减少计算量。样本增强在高光谱里特别重要因为标注样本少。常用的方法有随机翻转、随机旋转90度、加高斯噪声、波段随机丢弃。我试过在Indian Pines上做五折增强把每类样本扩到原来的8倍分类精度能提升3到5个百分点。但要注意增强后的样本不能跨训练集和验证集否则会数据泄漏。import numpy as np from sklearn.decomposition import PCA def extract_patches(cube, gt, patch_size32, stride16): h, w, b cube.shape pca PCA(n_components30) cube_pca pca.fit_transform(cube.reshape(-1, b)).reshape(h, w, 30) patches, labels [], [] for i in range(0, h - patch_size 1, stride): for j in range(0, w - patch_size 1, stride): patch cube_pca[i:ipatch_size, j:jpatch_size, :] label gt[ipatch_size//2, jpatch_size//2] if label 0: patches.append(patch) labels.append(label) return np.array(patches), np.array(labels)这段代码可以直接跑注意PCA要在整幅影像上拟合不能只在训练集上拟合否则验证集的分布会不一致。4. 典型应用场景与实操案例4.1 基于U-Net的遥感图像语义分割U-Net在高光谱分割里用得很多尤其是做地物面积估算。输入是降维后的patch输出是每个像素的类别概率。编码器用卷积加池化解码器用反卷积加跳跃连接。损失函数用加权交叉熵权重按类别频率的倒数设置这样能缓解类别不平衡。训练时batch size设16学习率1e-3用Adam优化器跑100个epoch。在Pavia University上U-Net的总体精度能到95%以上Kappa系数0.93左右。推理阶段用滑动窗口重叠率设一半最后取平均这样能消除拼接处的接缝。4.2 基于YOLOv8的高光谱目标检测YOLOv8原本是做RGB目标检测的但把输入通道改成高光谱波段数后也能用。关键是把高光谱数据转成伪彩色图像或者直接取前三个主成分当RGB。训练自己的数据集时标注文件用YOLO格式每行是类别 x_center y_center width height坐标归一化到0到1。数据增强用Mosaic和MixUp学习率用余弦退火从1e-2降到1e-4。在自建的农田地块数据集上YOLOv8的mAP能到0.85左右。但要注意高光谱的波段数多直接输入YOLOv8会导致计算量爆炸建议先用PCA降到3到5个波段或者用1x1卷积做波段选择。4.3 基于随机森林的传统分类不是所有场景都需要深度学习。样本量少、特征维度高的时候随机森林反而更稳。在Indian Pines上用原始光谱曲线加一阶导数特征随机森林的精度能到85%左右训练时间不到一分钟。参数调优主要看树的数量和最大深度树的数量设500最大深度设20基本够用。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( features, labels, test_size0.3, random_state42 ) rf RandomForestClassifier(n_estimators500, max_depth20, n_jobs-1) rf.fit(X_train, y_train) print(rf.score(X_test, y_test))随机森林的好处是可解释性强能输出特征重要性帮你判断哪些波段对分类贡献大。我试过在Salinas上做波段选择用随机森林的重要性排序取前50个波段精度只掉了1个百分点但计算量减少了一半。5. 常见问题与排查技巧实录5.1 下载链接失效怎么办公开数据集的链接失效是常态。我的经验是先看论文的补充材料很多作者会把数据放在Google Drive或者Dropbox上如果失效去Kaggle或者IEEE DataPort搜同名数据集通常有人搬运再不行就发邮件给通讯作者学术圈里要数据一般都会给。提示下载大文件时用下载工具比如aria2或者IDM支持断点续传避免下到一半断了重来。5.2 波段顺序对不上怎么排查不同传感器的波段顺序不一样AVIRIS是BIPROSIS是BIL国产数据有的是BSQ。读取后先看header文件里的interleave字段或者用cube.shape判断。如果形状是(h, w, b)说明是BIP如果是(b, h, w)说明是BSQ需要转置。转置用np.transpose(cube, (1, 2, 0))。5.3 训练时loss不下降怎么调高光谱分类loss不下降常见原因有三个学习率太大、数据没归一化、标签有噪声。先检查数据范围确保在0到1之间再把学习率降到1e-4试试如果还不行可视化几个样本的光谱曲线看看有没有异常值。我遇到过标签文件里背景值没清零的情况导致模型把背景也当一类学loss一直震荡。5.4 常见问题速查表问题现象可能原因解决方法下载链接打不开链接失效找Kaggle镜像或联系作者读取后形状不对存储格式不同检查interleave字段并转置反射率大于1未做大气校正走FLAASH或白板归一化训练loss震荡学习率过大降到1e-4并加梯度裁剪验证精度远低于训练过拟合加Dropout和数据增强推理结果有接缝滑动窗口重叠不足重叠率设50%并取平均5.5 独家避坑技巧第一个技巧下载数据集后先做一次全量备份放在两个不同的物理硬盘上。我吃过亏有一次硬盘坏了重新下载花了三天。第二个技巧用DVC或者Git LFS管理数据版本每次预处理后的数据都打标签这样实验可复现。第三个技巧切patch之前先做坏波段剔除用np.isfinite检查NaN用np.percentile检查异常值否则训练时会出现loss为NaN的情况。6. 数据集的扩展与二次开发6.1 自建数据集的标注流程公开数据集不够用的时候自建是唯一出路。标注工具用LabelMe或者QGIS前者适合做像素级标注后者适合做地块级矢量标注。标注完导出成GeoTIFF或者shapefile再用GDAL转成模型需要的格式。标注时注意类别定义要清晰比如“农田”和“草地”的边界要统一标准否则不同人标出来的结果不一致。6.2 多模态数据融合高光谱加LiDAR是现在比较热的方向。LiDAR提供高程信息高光谱提供光谱信息两者融合能提升分类精度。融合方法有早期融合和晚期融合早期融合是把LiDAR的强度和高程当成额外波段拼到高光谱立方体后面晚期融合是分别训练两个模型再投票。我试过在Pavia University上加模拟的LiDAR数据早期融合的精度比单模态高2个百分点。6.3 迁移学习与预训练ICVL和Harvard的样本量大适合做预训练。先在ICVL上训练一个自编码器学到光谱的通用表示再把编码器迁移到Indian Pines上做分类只需要少量标注样本就能达到不错的精度。这种方法在小样本场景下特别有用比如做矿物填图时标注样本可能只有几百个。import torch import torch.nn as nn class SpectralEncoder(nn.Module): def __init__(self, in_bands31, latent_dim64): super().__init__() self.encoder nn.Sequential( nn.Linear(in_bands, 128), nn.ReLU(), nn.Linear(128, latent_dim), nn.ReLU() ) def forward(self, x): return self.encoder(x)这个编码器结构简单但在ICVL上预训练后迁移到其他数据集上效果不错。关键是预训练时用重构损失迁移时冻结编码器只训练分类头。7. 工具链与效率提升7.1 Python生态核心库处理高光谱数据Python生态里最常用的库有scipy.io读.matrasterio读GeoTIFFspectral读ENVIscikit-learn做降维和分类torch和tensorflow做深度学习。spectral库虽然更新慢但读ENVI格式很稳建议装0.22版本。rasterio读大文件时用window参数做分块读取避免内存溢出。7.2 MATLAB用户的快速上手MATLAB在高光谱领域依然有优势尤其是hyperspectral工具箱。读数据用multibandread做PCA用pca分类用fitcecoc。MATLAB的优点是矩阵操作快可视化方便缺点是深度学习生态不如Python。我的建议是预处理和传统算法用MATLAB深度学习用Python两者通过.mat文件交换数据。7.3 计算资源规划高光谱数据量大Indian Pines的立方体是145乘145乘200约420万个浮点数内存占用16MB左右。但GF-5的幅宽是60公里空间分辨率30米单景影像有2000乘2000个像素330个波段内存占用超过5GB。处理这种数据需要至少32GB内存GPU显存建议8GB以上。如果资源不够用分块处理每次读一个窗口处理完写回磁盘。注意分块处理时块与块之间要留重叠区域否则拼接后会有接缝。重叠宽度至少等于patch尺寸。8. 个人实操体会与后续方向我在实际项目里最大的体会是数据集的质量比算法的复杂度更重要。同样一个U-Net在标注干净的Salinas上能到95%在标注粗糙的自建数据上可能只有70%。所以拿到数据后先花时间做数据清洗和标注校验比急着调模型参数划算得多。另外高光谱转反射率这一步不能省。我见过有人直接用DN值训练在训练集上精度很高换一景影像就崩了。反射率是物理量不同传感器、不同时相的数据才有可比性。如果实在做不了大气校正至少要做白板归一化把量纲统一。后续如果要做扩展我建议往两个方向走一是多模态融合把高光谱和SAR、LiDAR结合提升复杂场景下的分类鲁棒性二是自监督预训练用大量无标注高光谱数据学表示再迁移到小样本任务上。这两个方向目前都有开源代码可以参考上手门槛不算高。最后分享一个小技巧下载数据集时把下载链接、文件MD5、预处理脚本放在同一个文件夹里用README记录每一步操作。这样过几个月再回头看能快速复现实验不用重新踩坑。