遥感云检测利器Fmask:单景多光谱影像的判据与工程调优

发布时间:2026/10/4 6:19:25
遥感云检测利器Fmask:单景多光谱影像的判据与工程调优
Fmask 这个算法在遥感圈子里不算新东西但直到今天做单张多光谱影像的云检测它依然是绕不开的标杆。很多人一听说云检测下意识就想用时间序列、多时相合成那套思路但实际工程里更多时候你手里只有一景单时相影像没得选。Fmask 恰恰就是针对这种场景设计的只用一幅多光谱图像就能把厚云、薄云、云阴影、雪和水体一次性帮你标注出来。这篇东西我不会跟你念论文就按我实际跑各种数据、调各种参数的经验把 Fmask 的判据逻辑、实操流程和那些文档里不会写的坑一次性说清楚。1. Fmask 在解决什么问题1.1 云检测的痛点和单张影像的独特优势做遥感定量反演或者地表分类的时候云是最常见也最烦人的干扰。有云的地方地表信号直接被遮挡或者被散射污染你要是硬着头皮把这些像元拿去做 NDVI、做温度反演出来的结果基本没法看。传统的做法里很多人倾向于用多时相方法比如连续几天的影像叠在一起找那些反射率波动大的像元判定为云。这个方法理论上有效但前提是你得有足够多、足够近时相的影像而且还得做配准。放到实际项目中经常是研究区一年到头就那么一两景无云影像或者某个时相的数据必须用你根本凑不出时间序列来。Fmask 的出现正好补齐了这个空缺。它对社会公开、适用面广核心思路就是只用单景影像结合物理规则和概率统计把云层检测出来。它的全称是 Function of mask最早是澳大利亚学者提出的后来在 Landsat 系列上被大规模验证过近几年也扩展到了 Sentinel-2 这类新一代多光谱卫星。单张影像做检测的好处很直接第一你不用等邻近日期数据处理效率大幅提升第二逻辑是逐像元独立判断对传感器波段配置的依赖是可控的换卫星平台时迁移成本相对低。1.2 单景检测的底层逻辑为什么不用时间序列也能分得清Fmask 能单张检测的核心并不是它比深度学习模型更“智能”而是它充分利用了云在物理属性上的特殊性。云层有几个天然特征云顶温度远低于常温地表尤其是在热红外波段上表现极其明显厚云在可见光波段反射率极高又白又亮薄云在卷云波段约 1.36~1.38 微米有非常独特的吸收和散射响应。这几个特征叠加在一起就形成了一条相对清晰的判定链先筛选出“可能是云的候选”再结合归一化雪指数、亮度概率和温度概率去剔除误判。你可能要问既然亮目标这么多为什么还能分得开这是因为 Fmask 不是只看一个条件而是做了一个“证据链”。比如一片积雪它虽然也很亮但在热红外波段的亮温和云差得很远同时它在短波红外波段的吸收特征和云完全不同。又比如沙漠和亮建筑它们反射率高但卷云波段几乎没有信号。Fmask 把热红外亮温、卷云波段反射率、归一化植被指数 NDVI、归一化积雪指数 NDSI 等放在一起投票综合判断这比任何单一阈值的“一刀切”都稳健得多。2. Fmask 的内部判据与实现细节2.1 厚云最直观的候选区是怎么圈出来的Fmask 的检测流程大致分两步第一步是逐像元产生潜在云的布尔掩膜第二步是用对象分割和目标聚类来做最终判决。先说厚云。在 Landsat 8 OLI 数据里厚云候选区通常用一组阈值组合来圈定比如说蓝波段Band 2反射率大于 0.20~0.30、绿色波段Band 3反射率大于 0.20、短波红外波段SWIR1Band 6反射率较低但可见光很高同时热红外亮温低于 287.5K 左右。这组阈值看起来好像很粗糙但它是从全球多幅影像里统计出来的经验值对大多数地表类型都有不错的区分度。实际操作中我一般不会直接套论文里的数字而是会先看我手头影像的辐射定标结果。如果影像的反射率尺度是 0~10000 这种整型值那阈值就必须先除以 10000 再比较否则会把大量暗地表误判成云。这里有个小经验通了 Fmask 处理链路后你可以先把没有云的已知区域提取出来看看阈值分布反过来验证自己有没有搞错单位。单位的坑我踩过不止一次Landsat Collection 2 Level-1 产品的反射率已经做了大气校正和 Collection 1 的原始 TOA 反射率数值范围完全不同阈值直接搬会出大问题。2.2 薄云和卷云波段最容易漏掉的信号怎么抓厚云好检真正头疼的是薄云。薄云在可见光波段的反射率不高混在地表信号里肉眼都很难分辨普通阈值法根本没法把它和裸土、干植被区分开。Fmask 对付薄云的大杀器是卷云波段。以 Landsat 8 为例Band 9 的中心波长在 1.38 微米附近这个波段非常特殊绝大多数地表辐射在这段几乎被大气水汽吸收殆尽传感器能接收到的信号主要来自高云和薄卷云对太阳辐射的散射。所以只要 Band 9 的反射率明显高于背景噪声基本可以断定这个像元有卷云污染。在实际设定 Band 9 阈值时参考值通常取 0.03 左右但这并不是铁律。高海拔地区的薄雪和部分裸岩在 1.38 微米也可能有微弱信号容易造成虚警。我的建议是如果处理的是多山区域把 Band 9 的阈值适当调高到 0.04~0.05同时增加一个条件要求可见光波段反射率不能太低这样就能把一些暗色岩石表面排除掉。薄云检测在农田、裸土区域特别有用你光靠 RGB 合成图根本看不见那些云但 Fmask 能帮你标出来这直接影响了后面地表反演的精度。2.3 水体、雪和云阴影分类不是终点滤除才是目的Fmask 的输出里除了云掩膜还会顺带输出水体掩膜、雪掩膜和云阴影掩膜。很多人误以为这些是副产品其实它们在云检测流程里扮演着关键角色。水体检测用的是 NDVI 和 NDWI 的组合水体在近红外波段反射率低在绿波段反射率相对略高所以 NDWI 通常大于 0而 NDVI 往往是负值。雪检测用的是 NDSI即绿波段和短波红外波段的归一化比值积雪的 NDSI 通常在 0.4 以上。之所以必须先确认水体、雪的位置是因为它们经常和云影混在一起。尤其是水体水体在暗背景下本身就很容易被误判为云阴影。先识别水体再把它排除出云阴影候选区能显著降低误检率。云阴影的检测在 Fmask 3.x 版本里用了更聪明的方法先根据云的位置、高度和太阳几何参数估算阴影应该落在哪个方向多远的距离再在这个预测区域内寻找暗像元配合形态学膨胀做匹配。这比单纯找“比周围暗”的像元靠谱得多能避免把山体阴影、水体误判成云阴影。单张影像检测阴影之所以可行核心在于 Fmask 用云的位置几何推算阴影的“可能性范围”而不是在整个场景里大海捞针。3. 实操流程与参数调优3.1 版本选择与数据准备Fmask 目前主流有两个形态一个是官方或社区维护的 C 版本打包成命令行工具另一个是 Python 封装版比如基于 Python 3 的 PyFmask 和 Fmask 4.x 系列。我自己的使用习惯是优先用 Python 版因为后续要集成到自动化批处理流程里更顺手而且可以方便地跟 GDAL、NumPy 配合做自定义修改。数据准备上Landsat L1 级别产品就可以直接喂给 Fmask不需要预先做大气校正。但有一点必须注意Fmask 的输入依赖热红外波段Landsat 8/9 是 Band 10 和 Band 11Sentinel-2 则没有热红外波段所以如果要处理 Sentinel-2必须依赖 Fmask 专门适配 Sentinel-2 的版本如 Fmask 4.5 或 Sen2Cor 相关扩展。以 Landsat 8 为例你需要准备的文件包括各波段的 GeoTIFF、MTL 元数据文件以及可选的太阳几何角度文件。Fmask 会从 MTL 里自动读取太阳高度角、方位角这些参数用于云阴影投射计算。3.2 核心参数怎么调温度、反射率、概率阈值Fmask 的判决过程不是简单的布尔运算而是把多个特征转成概率最后比大小。以下是我整理过的、最常用的几个参数节点参数节点常见参考值调整方向与场景我的经验热红外亮温阈值287.5K高原、高纬度区域适当降低到 280~285K夏季影像容易把高温裸地混入云候选需要结合 NDVI 辅助判断卷云波段阈值0.03干燥裸土区域调到 0.04~0.05有薄雾霾时这个值要放低否则漏检明显NDSI 雪阈值0.40多雪区域保持 0.35~0.40 之间城市亮屋顶容易与雪混淆加一条 SWIR 反射率限制更稳最小云像元数默认 10减小到 3 能识别碎云但碎云密布时会增加噪声我通常保持默认碎云交给后处理合并阴影搜索方向数量默认 8 方向山区影像有时减少到 4 方向减少误投射方向太多会产生大量阴影候选后用暗像元约束筛选实际使用过程中我不会把这些参数单独割裂来看。Fmask 的概率判决是把潜在云像元的温度概率和亮度概率乘起来得到最终的“云概率”再根据阈值决定是不是云。如果影像地形复杂我会把温度之门即热红外亮温的上限放宽一点防止高海拔冷地表被排除出候选如果处理的是城市影像我会收紧亮度概率因为高楼、玻璃幕墙的反射率特征实在太像云了。3.3 一次完整的 Fmask 流程示例下面我给出一次我在 Landsat 8 影像上跑 Fmask 的完整操作方便对照。假设你已经下载好了 L1TP 产品解压后目录里有LC08_L1TP_XXX_MTL.txt和各波段 TIFF。第一步先确认 Python 环境和依赖。我用的版本是 Python 3.9搭配 GDAL 3.4 以上、NumPy、SciPy 和 scikit-learn。Fmask 的 Python 版在安装时要用到pip install fmask但部分版本依赖了旧的pyToll等库建议直接用 Anaconda 建一个独立环境避免把系统环境搞乱。conda create -n fmaskenv python3.9 conda activate fmaskenv pip install fmask pip install gdal numpy scipy scikit-learn第二步准备输入。Fmask 4.x 支持直接读取 Landsat 的 MTL 文件你只需要指定 MTL 文件路径即可。它会自动从 MTL 中解析波段文件名和太阳几何参数。如果你的影像区域包含海岸带最好额外准备一个水陆掩膜文件可以显著减少近岸浪花被误判成云的概率。我在处理沿海城市影像时都会额外叠加一个水陆掩膜Fmask 自带的海陆库在某些低分辨率数据上不够精细。第三步执行命令。以命令行方式运行python -m fmask.sentinel2stacker --mtl LC08_L1TP_XXX_MTL.txt python -m fmask.fmask --mtl LC08_L1TP_XXX_MTL.txt -o LC08_fmask_out.tif如果是用 Python API 的方式集成到自己的处理流程里核心调用逻辑大概是这样from fmmask import fmask from fmmask.config import FmaskConfig config FmaskConfig() config.set_input_mtl(LC08_L1TP_XXX_MTL.txt) config.set_output_file(LC08_fmask_out.tif) fmask.run(config)LC08_fmask_out.tif输出的是一个多波段掩膜文件其中通常包含云、云阴影、雪、水体和清晰地表这几类的类别编号。我一般会把输出转换成四分类云、阴影、雪水、清晰再在后处理里把零碎的云像元用形态学开闭运算清理一下。输出结果别急着用一定要和真彩色合成图叠在一起看一遍Fmask 是概率方法误检不可避免目视抽检是最后一道保险。4. 常见问题与排查技巧实录4.1 误检和漏检Fmask 最常见的五种翻车现场我整理了这几年用 Fmask 反复遇到的典型问题放在表格里每条都附了排查思路方便你对号入座。问题现象可能原因我的排查和处理方法城市中心大片亮区被标记为云高楼、玻璃幕墙的可见光和热红外特征与云高度相似本质原因是热红外亮温并没有显著低于地表可以手工调整温度概率权重或叠加一个城市不透水面图层做后滤波高山积雪被误判为云雪在可见光很亮NDSI 虽高但部分区域积雪和云混合在输出后处理中用 NDSI 大于 0.4 且 SWIR1 反射率小于 0.2 的规则把雪从云中剥离薄云大量漏检卷云波段阈值偏高或者影像本身没有卷云波段Landsat 7 ETM 没有卷云波段我会改用可见光热红外组合来勉强弥补但漏检率确实更高大片水体被标为云阴影深色水体的暗反射率特征与云阴影太接近先运行 NDWI 水体掩膜把水体范围膨胀几个像元之后再排除出阴影候选区海岸带浪花白沫被检出云泡沫的高反射率以及没有热红外响应导致阈值失效在海陆掩膜基础上直接把距离海岸线 100~200 米范围内的像元标记为潜在误检区再人工复核4.2 真正的实操心得如何让 Fmask 结果更可用Fmask 是单景检测所以在碰到影像质量参差不齐的情况下后处理比调参数更容易见效。我用得最顺手的套路是先用 Fmask 生成初版掩膜然后把这个掩膜和自己的业务规则做交集。比如做植被定量反演时我会额外要求云概率大于 0.7 才算云云阴影概率大于 0.6 才算阴影宁可让边界稍微松弛一点也不要因为过分保守去掉大面积的无效像元。另外如果处理的是批量影像每次只调一组全局参数大概率是不行的。Fmask 对季节敏感夏季的亮温阈值和冬季应该不一样这一点在论文里没有强调但在工程里非常关键。我通常是把一年影像按季度分组每个季度单独跑一组阈值误检率能下降三成左右。对于处理大范围区域的研究者这个做法几乎属于必备技巧。还要提醒一点Fmask 的热红外波段对部分传感器来说是独立文件。Landsat 8 的 Band 10 和 Band 11 需要重采样到和可见光波段一致的空间分辨率再参与运算Fmask 内部会自动处理但如果你是自己改代码绕过 Fmask 的主流程一定要记得这一步。否则热红外波段和可见光波段像元不对齐云边缘会出现一圈“伪云环”。另外在部分 Fmask 版本里海陆掩膜数据如果和影像分辨率不匹配也会导致海岸线附近的检测结果呈锯齿状我通常会在预处理阶段手动把海陆掩膜重采样到与影像一致。4.3 质量评估怎么判断 Fmask 结果靠不靠谱最后聊一下如何定量评估 Fmask 的精度。做研究或者写报告时不能只给一张分类图说“看起来不错”还是要有量化指标。最常用的做法是随机抽样把影像上的像元分成云、非云两类和人工目视解译的结果做混淆矩阵。我习惯在每个场景里抽样 300~500 个点保证云和非云都覆盖。然后算准确率、召回率和 F1 分数。Fmask 在厚云检测上召回率通常可以做到 90% 以上但在薄云和云阴影上会低一些这是它的固有局限不用强求。还有一个偏经验性的指标检查云掩膜的边缘一致性。如果掩膜边缘在 30 米分辨率影像上非常“碎裂”说明参数过于激进如果边缘圆整得像手工画出来的可能是把地盘过度膨胀了。理想的云掩膜边缘应该和目视可见的云边界贴合同时又有一些小尺度凹凹凸凸的真实感。这一点靠目视检查就能判断个八九不离十。我最近在推进的一个批处理流程里核心就是用 Fmask 先做初筛再把初筛结果和一个轻量级深度学习云检测模型做投票融合。深度学习模型擅长识别复杂的云纹理Fmask 则擅长利用热红外和卷云波段做物理约束两者互补之后误检率从单独用 Fmask 的 6% 降到了 3% 左右。这个思路你可以参考但不一定要上深度学习哪怕只是把 Fmask 和水体掩膜、积雪掩膜做叠加决策精度提升也很明显。跑 Fmask 这几年我最大的体会是任何云检测算法都不能保证百分之百准确它的价值在于帮你把大量明显、好识别的云像元快速剔除把真正难啃的硬骨头数量压缩到人工可以复查的范围。与其花大把时间调整无数个阈值追求“完美掩膜”不如接受它的定位——做一个快速可靠的粗筛工具然后在业务判断上留出人工干预的空间。这样用 Fmask你会发现它其实是遥感预处理链里最省心的一环。