简介:这是一份面向遥感、地学与农业等领域研究者的R语言高光谱数据分析开源资源,围绕hsdar包提供从数据导入、预处理、特征提取到分类建模的完整处理思路,适合具备基础R使用经验、希望快速上手高光谱数据管理与分析的读者。资源压缩包共224个文件,约3.73MB,以R脚本(.r)、Rd文档(.rd)、Fortran源代码(.f90/.f)、示例数据与PDF说明为主,还包含C、RData、图表及编译配置文件等,便于学习源码实现、查阅函数用法并复现分析流程。内容涵盖ENVI、HDF、GeoTIFF等格式数据读取,光谱平滑与大气校正,PCA/ICA/PLSR降维,SVM与随机森林分类,以及回归建模和可视化等关键环节。目前已有740人学习浏览,能够帮助用户快速构建从原始数据到解释结果的高光谱分析路径,对科研与工程应用均有较强参考价值。 做高光谱数据分析这几年,我先后折腾过ENVI、Python、Matlab,最后还是把R当成了主力。原因很简单:R在光谱数据统计分析上的生态太成熟了,而且整套工具链完全开源,配上一个hsdar包就能覆盖从数据读取、预处理到建模分析的大部分流程。今天不聊那些虚的,直接把我用R处理高光谱数据的完整思路和踩过的坑分享出来,适合刚接触高光谱数据、又不想在商业软件上花冤枉钱的研究生和科研人员参考。
1. 高光谱数据的特点与R选型逻辑
1.1 高光谱数据到底长什么样
高光谱数据和普通图像最大的区别在于,它有几十到几百个连续波段。以我常用的机载高光谱数据为例,通常覆盖400到2500纳米范围,光谱分辨率在5到10纳米之间,单景数据就是几百个波段的“三维立方体”。很多刚上手的朋友容易懵,是因为不知道这个三维结构怎么在R里面表示、怎么索引。
其实高光谱数据在R里就是两个东西的组合:一个是像元的空间位置信息,另一个是每个像元对应的光谱曲线。如果你把数据展平,本质上就是一个大矩阵,行是每个像元,列是波段。R处理这种矩阵结构天然有优势,尤其是后续做PCA、聚类、回归这些统计分析时,R的统计建模能力比ENVI自带的工具强太多。
1.2 为什么选择R而不是Python或商业软件
我知道Python也有spectral库,但如果你做的是科学研究,需要交代统计方法的细节,R的文档和论文支持明显更友好。举个实际例子,我早期用Python提取光谱特征,到了做PLSR回归那一步,Python需要自己拼装各种库,而R里一个pls包就全搞定了,还自带交叉验证和可视化。
商业软件当然好用,像ENVI的一键式操作确实省心,但问题在于:贵,而且闭源,你没法知道每个处理步骤的数学原理。R的好处是每个函数的源代码都是开放的,出了问题可以直接翻源码看实现逻辑,这个对科研工作的可复现性来说太重要了。另外,R的社区包更新速度很快,很多最新发表的算法,隔几个月就有对应的R包实现,这在ENVI里是等不到的。
2. 环境搭建与R包选型实战
2.1 核心R包安装清单和用途
R处理高光谱数据的核心包其实就那几个,按处理流程排列如下:
- hyperSpec:读取和操作高光谱数据的基础包,支持ENVI、FIA等常见格式,也可以把光谱数据存成hyperSpec对象,方便后续切片、分组、绘图。
- hsdar:高光谱遥感专用包,能够计算各种植被指数、实现包络线去除(continuum removal)、光谱特征提取等功能,是我们做光谱分析的主力。
- prospectr:做光谱预处理特别好用,包括Savitzky-Golay平滑、标准正态变换(SNV)、多元散射校正(MSC)、一阶二阶导数计算等。
- pls:偏最小二乘回归的经典R包,做光谱定量分析必备。
- caret:统一模型训练和调参框架,搞分类和回归模型时方便做交叉验证。
安装时直接用install.packages就行,如果提示缺少系统依赖,一般是gdal或者proj库的问题,Windows用户建议直接装RTools,Linux用户可以用apt安装libgdal-dev解决。
2.2 数据准备阶段的注意事项
读数据之前有一件事特别重要:确认你的数据是怎么来的。我接手过很多数据,有的是别人导出的文本表格,一列是一个波段,一行是一个样点;有的是成熟的ENVI标准格式,.hdr文件加.dat文件;还有的是从成像光谱仪直接导出的原始cube文件。不同来源的数据在R里的读取方式完全不同。
如果是ENVI格式,hyperSpec包里的read.ENVI函数可以直接读,但其要求很严格,必须保证hdr文件的波段信息正确。我一开始不知道这个坑,用别人处理过的数据经常读不进去,后来学会先打开hdr文件检查,确保里面有波段数量、波长范围和数据类型这几项,问题就解决了一大半。如果是文本格式,read.csv直接读进来,自己构建光谱矩阵就行。
3. 高光谱数据的预处理流程拆解
3.1 辐射校正与反射率转换
很多朋友拿到手的数据,第一反应就是直接开始分析,这是个大坑。从仪器上导出的原始数据,保存的是数字量化值,即DN值,它受到暗电流、光照条件、仪器响应等因素的影响,不能直接用来做光谱间的比较。
正确的做法是先做反射率转换。如果数据供应商已经帮你做了这一步,数据里存的就是反射率值,那就可以跳过;如果拿到的还是DN值,你可以用暗校正板或白板数据进行计算。在R里面实现很简单,直接用每个波段的DN值除以对应波段白板的DN值,再乘上白板的标准反射率就行。说白了就是逐波段的除法运算,用hyperSpec对象一行代码就能搞定:
# 假设dat是待校正数据,white是白板光谱数据 reflectance <- dat / white这个过程我建议一定要做,很多光谱指标的计算对反射率的绝对值很敏感,跳过这一步会让后续分析精度大打折扣。
3.2 光谱平滑与噪声去除的窗口选择
高光谱数据在个别波段区域信噪比特别差,比如大气吸收带附近的波段,在1400纳米、1900纳米附近会有明显的噪声谷。这时候就需要做光谱平滑。我常用的方法是Savitzky-Golay平滑,它的好处是在去除噪声的同时能保留光谱的峰谷形状。
prospectr包里的savitzkyGolay函数参数不多,关键是选对窗口大小和多项式阶数。这里我踩过坑:窗口太小,噪声滤不掉;窗口太大,会把有用的光谱特征磨平。以波段间隔为5纳米到10纳米的数据为例,我一般选窗口尺寸为11到15个波段点,多项式阶数设为2。如果你的数据光谱分辨率低,波段间隔大,可以适当减小窗口。做完平滑后,强烈建议把处理前后的光谱曲线叠在一起对比看,确认特征峰没有明显变形。
3.3 波段筛选与数据降维的实操细节
高光谱数据波段多,但波段之间的冗余也大。很多人在完成预处理后直接丢进模型,结果过拟合得一塌糊涂。我在实际工作中,通常会先用方差过滤掉那些几乎恒定的波段,再用连续投影算法或者随机森林变量重要性排序做进一步筛选。
hsdar包里的波段选择函数和一些特征提取方法可以配合使用。另外,PCA也是我常用的降维手段。R里用prcomp函数做PCA之后,可以画出碎石图看前几个主成分的贡献率。做高光谱分类时,我一般取累计贡献率超过95%的前若干个主成分作为输入特征,效果比直接用全部波段稳定很多。
4. 光谱指数计算与包络线去除分析
4.1 常用遥感指数的R实现
光谱指数是高光谱分析中最常用的工具,像NDVI、EVI这些植被指数大家都很熟了,但高光谱数据的能力远不止于此。因为波段足够多,我们可以精确提取红边位置、计算各种窄带指数,这些指数对作物生化参数的反演比宽波段指数敏感得多。
在hsdar包里,计算植被指数非常方便。包内自带的spectralIndices函数一次可以计算几十个常见指数,你只需要指定光谱数据对象和波段范围。举个实际例子,我计算归一化植被指数时,需要同时知道红光波段和近红外波段的位置:
# 用hsdar包计算NDVI library(hsdar) # 假设spec是hyperSpec对象,需要先转换为Speclib对象 spc <- as.speclib(spectra, wavelength) ndvi <- spectralIndices(spc, "NDVI")这里有个小提示:如果你的数据波段范围不够覆盖660纳米和800纳米附近,算出来的NDVI就不靠谱,这类指数在计算前一定要先检查波段覆盖范围。
4.2 包络线去除的原理与实操
包络线去除,也叫连续统去除,是高光谱特征分析的经典方法。它的作用是把光谱曲线归一化到一个共同的基准线上,消除光照、地形等因素的影响,同时突出光谱的吸收特征。原理其实不复杂:先拟合出光谱曲线的包络线,然后用原始光谱除以包络线,得到的数值范围在0到1之间,波谷就是吸收特征的位置。
hsdar包中包络线去除有现成函数,但我建议你去翻一下源码,理解它的插值算法是怎么实现的,这样后面调参数时就不容易出错。操作上,先对光谱对象做包络线去除,再针对特定吸收特征(比如叶绿素在680纳米附近的吸收峰)提取特征参数,包括吸收深度、吸收宽度、吸收面积等,这些参数是后续分类或回归建模的关键输入。
我在做植被病害检测时,就是用包络线去除后的吸收深度来量化叶绿素降解程度,效果比直接用原始反射率好很多,因为去除了背景信号的干扰。
4.3 光谱角度制图与分类实战
分类是高光谱数据应用的重要方向。使用R做分类时,我比较推荐光谱角度制图方法,它把每个像元的光谱视为多维空间中的一个向量,用向量间的夹角来衡量光谱相似度,对光照变化不敏感。
R中实现光谱角度制图并不复杂,可以自己写一个函数,先计算参考光谱与目标光谱之间的夹角余弦,再设置阈值分类。参考光谱可以从样地实测数据或纯像元平均获得。实测下来,这种方法在植被类型分类时表现稳定,尤其是类间差异较小的情况下,比单纯用欧氏距离要好。
如果你的数据量大、类别多,也可以考虑SVM或随机森林模型。caret包提供了统一的接口,配合doParallel进行并行计算,处理几百万像元的数据也不会慢得离谱。分类完成后记得做精度评价,用混淆矩阵和Kappa系数评估结果,这步在写论文时是必须的。
5. 高光谱可视化的几个常用套路
高光谱数据可视化是很多人的痛点。普通RGB图像只能显示三个波段,而高光谱数据动辄上百个波段,怎么把信息有效地展示出来,直接影响你对数据的理解和最终成果的表达。
我常用的几个可视化方案如下:
- 单波段灰度图:用来快速查看某个特定波长下的空间分布,比如查看红色波段下的植被区域,直接plot就能出图。
- RGB真彩色或假彩色合成:从数据中挑选三个波段分别赋给红绿蓝通道,比如用近红外、红光、绿光波段做假彩色合成,植被在图上就会显示为亮红色,视觉上非常直观。
- 光谱曲线图:展示单个像元或区域平均光谱时,用ggplot2绘制x轴为波长、y轴为反射率的折线图,多组光谱可以用不同颜色区分。
- 分类结果专题图:用raster包将分类结果输出为栅格,结合tmap包做交互式制图,效果非常好。
这里分享一个技巧:如果想把光谱曲线的多个波段特征同时展示在一张图上,可以先把光谱数据缩放归一化到0到1,再按波段位置错位绘制,形成“光谱堆叠图”,这种图在开组会时展示特别直观。
6. 常见报错与排查经验实录
R处理高光谱数据的坑是真的不少,很多问题不是代码写错了,而是数据本身或者R包的使用方式不对。我把这两年遇到的典型问题整理成表格,方便大家排查。
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 读取ENVI数据提示“data format not supported” | hdr文件里的数据类型设置不对,比如真实数据是浮点型,hdr文件却写成整型 | 打开hdr文件,检查data type字段,用文本编辑器修改成正确的数值类型 |
| 计算光谱指数时报错,提示波长范围不对 | 数据的波长单位不统一,有的是纳米,有的是微米 | 统一波长单位到纳米,用wavelength()函数查看并乘以1000转换 |
| 绘图时出现大量噪音和尖刺 | 没有做光谱平滑,或者平滑窗口太小 | 用savitzkyGolay函数重新处理,窗口适当加大 |
| PCA结果内存不足,程序崩溃 | 数据矩阵太大,一次加载了整个影像立方体 | 分块读取,用raster包处理大影像,或者抽样部分像元进行探索性分析 |
| SVM分类训练时间过长 | 样本量太大或特征维度太高没有降维 | 先做PCA或波段筛选,再训练模型,可并行加速 |
6.1 一个典型的波段单位坑
这个我单独拿出来说,因为它太隐蔽了。某次我从一台成像光谱仪导出数据,波长信息在hdr文件里显示是400到1000,我以为是纳米,结果跑光谱指数计算时,hsdar包提示波段超出可见光范围。排查了半天才发现,这台仪器的波长单位其实是微米,也就是说400到1000是0.4到1.0微米。换算成纳米后一切正常。
所以拿到任何数据,第一件事就是打印出波长信息,再用plot函数画出几条光谱曲线,肉眼确认一下形状是否符合预期。花两分钟做这个检查,能省下后面排查问题的一整天。
6.2 内存管理心得
高光谱影像的像元数量和波段数量乘起来,数据量非常可观。一个1000乘1000像元、200个波段的影像,浮点型存储大概是1.6GB,在R里处理时内存占用还会翻倍。
我的做法是:能不加载全图就不加载全图。做统计分析时,先从影像中均匀抽取一定比例的像元作为样本来建模;把模型训练好之后,再用predict函数逐块预测整个影像,最后拼接起来。这样做内存压力小,而且因为模型已经固定,结果和全量计算几乎一致。raster包里的blockSize函数和writeRaster函数配合使用,可以很优雅地实现分块读写。
7. 从数据到成果的完整实操流程
最后把我近期一个完整项目的流程捋一遍,大家可以当作模板参考。这个项目是对一组小麦田的高光谱影像做叶绿素含量反演,数据是机载高光谱,空间分辨率0.5米,波段范围400到1000纳米,共128个波段。
实际操作中我的步骤如下:
- 先读入ENVI格式数据,打印波长信息确认波段范围。
- 用暗电流白板数据做反射率转换,并用savitzkyGolay平滑光谱。
- 剔除1400纳米前后的噪声波段区域,保留400到1300纳米的波段参与分析。
- 按感兴趣区域提取一定数量的样点光谱,和实测SPAD值一一对应。
- 做MSC预处理,再计算光谱植被指数和包络线去除吸收特征参数。
- 把指数和特征参数整合成建模矩阵,使用caret包随机划分训练集和验证集。
- 用pls包做偏最小二乘回归建模,用交叉验证选择潜变量个数。
- 最终模型在验证集上的决定系数是0.82,均方根误差2.3 SPAD单位,效果可以接受。
- 用最终模型对整个影像逐块预测,输出叶绿素含量空间分布图。
从开始分析到出图,整个过程完全在R里完成,没有使用任何商业软件,数据和脚本打包后可以在任何一台装了R的机器上复现,这种可复现性在论文投稿时是个很好的加分项。整个流程跑顺之后,再遇到类似的高光谱数据处理任务,基本上半天就能完成从数据到结果的闭环。
最后再分享一个小技巧:R里的hsdar包和hyperSpec包有非常详细的文档和论文引用要求,如果你在论文里用了这些包,记得引用相应的文献。很多审稿人会关注这一点,引用规范既能体现专业性,也是对这些开源包开发者的一种尊重和支持。
本文还有配套的精品资源,点击获取