简介:面向遥感数据处理与地表参数反演需求,这份Acolite大气校正工具包提供了可直接运行的Python程序与依赖模块。基于MODTRAN/6S辐射传输模型思路,工具可对Landsat、Sentinel等多光谱影像开展大气散射与吸收校正,输出地表反射率结果,适用于科研、环境监测及土地利用分类等场景。包内共762个文件,主要包含398个pyc编译模块、209个py脚本、95个txt参数/说明文件、28个csv系数表以及cfg、sample、json等配置样例,覆盖模型参数配置、卫星波段系数、运行入口与辅助数据,整体约3.59MB,轻量且模块划分清晰。已有1160人学习下载,适合需要快速搭建Acolite环境或对照源码理解大气校正流程的遥感初学者与研究人员。
1. Acolite 与 7z 压缩包:一个包把水色大气校正的工作流装全了
做水色遥感的人,电脑里大概率都存过一个叫 acolite.7z 的压缩包。Acolite 是专门面向水体的大气校正工具,输入哨兵二号或 Landsat 的 L1C 反射率影像,输出水面遥感反射率 Rrs,可以直接对接叶绿素、悬浮物、透明度反演。它不是一个安装包,解压后就是包含 Python 源码、配置与查找表的运行目录,所以 7z 解压、Python 环境和参数设置,是从下载到出图的三个真实门槛。
这篇笔记按我的使用路径组织:先讲 acolite.7z 在不同平台上的解压,再讲 Acolite 的原理与 Sen2Cor、6S 的选型差异,给出一景影像的最小命令与核心参数,最后把高频踩坑和验证习惯写在一起。适合正在做湖泊、水库、近岸水色遥感,又不信任通用陆地大气校正产品的人。
2. 把 acolite.7z 解压到能用:Linux、Windows 与 PyCharm 下的 7z 处理
2.1 为什么发布物偏爱 7z:高压缩率与“免安装”运行时
Acolite 不是 pip 包,发布物通常是一个完整的目录树:入口脚本、配置文件、查找表、示例数据都放在一起。用 7z 打包能在同样体积下容纳更多查找表,压缩率比 zip 明显高一截;对使用者来说,解压后不需要跑安装程序,路径配置对就能直接运行。关键点是解压时必须保留目录结构——如果你把 7z 当成 zip 那样“全部释放到同一个文件夹”,Acolite 会找不到自己的数据子目录,运行时报错看起来像代码问题,实际是路径问题。
所以我每次拿到 acolite.7z,第一件事不是急着解压,而是先确认手上有没有可用的 7z 命令行工具。Windows 用户习惯右键解压,但 Linux 服务器上默认不带 7z,这也是不少人在远程环境里卡住的第一道坎。
2.2 Linux 下解压 acolite.7z:一条命令保住目录结构
Linux 上解压 7z 文件,最常见做法是装 p7zip。Debian/Ubuntu 系的安装命令是apt install p7zip-full,CentOS/RHEL 系是yum install p7zip,包名不同但命令行工具都叫 7z。
# Debian / Ubuntu sudo apt install p7zip-full # 进入下载目录,保留目录结构解压到指定位置 cd ~/downloads 7z x acolite.7z -o/home/user/tools/这里x表示解压并保留压缩包内的目录结构,-o指定输出根目录。注意-o与路径之间没有空格,这是 7z 命令容易忽略的细节。与之对应的e参数会把所有文件平铺到同一个目录,Acolite 解压后找不到依赖目录,这种情况我见过不止一次。
解压完成后,建议立刻做一次完整性校验:
7z t acolite.7zt参数逐文件测试 CRC 校验值。我更习惯在下载后、解压前先测一遍,这样能把“压缩包坏了”和“环境配置问题”明确区分开,省得后面排错时两头怀疑。
2.3 Windows 下打开 7z:GUI 与 PowerShell 两种做法
Windows 系统默认解压不支持 7z,最常见的是安装 7-Zip 客户端。装好后右键 acolite.7z,选“7-Zip → 释放到 acolite\”,注意不要选“释放”或“提取到当前位置”。原因和 Linux 一样:要保留压缩包内的目录结构,否则 Acolite 运行时会找不到自己的数据目录。
需要命令行场景时,可以这样调用:
# 假设 7-Zip 装在默认路径 & 'C:\Program Files\7-Zip\7z.exe' x acolite.7z -oC:\tools\PowerShell 里路径含空格时,用&调用并给可执行文件路径加引号,-o后面同样不加空格。如果机器上没有 7-Zip 且能联网,可以顺手用 winget 装:
winget install 7zip.7zip无论哪个平台,解压路径都不要出现中文和空格。Acolite 内部通过 GDAL 读取影像,GDAL 对非 ASCII 路径的支持极差,出问题后表现很像“数据损坏”,其实是路径在捣乱。
2.4 在 PyCharm 里处理 7z:外部工具与 py7zr 两条路径
很多做遥感开发的人习惯把 Acolite 放进 PyCharm 项目里阅读和调用,但 PyCharm 编辑器本身不认识 7z。常见做法有两个。
第一种,把 7z 注册成 PyCharm 的外部工具。在 Settings → Tools → External Tools 里添加一条,Program 填C:\Program Files\7-Zip\7z.exe,Arguments 填x -o"$ProjectFileDir$\out" "$FilePath$",Working directory 填$ProjectFileDir$。这样在项目树里右键 7z 文件,就能直接解压到项目下的 out 目录,省去切到文件管理器再解压的步骤。
第二种,数据量不大时,用 py7zr 在代码里直接解压:
import py7zr archive_path = "acolite.7z" extract_dir = "./tools/acolite" with py7zr.SevenZipFile(archive_path, mode="r") as archive: archive.extractall(path=extract_dir) print("解压完成:", extract_dir)py7zr 是纯 Python 实现的 7z 库,好处是不依赖本机安装 7-Zip,适合写自动化流水线;缺点是解压速度比原生 7z 慢不少。acolite.7z 这种体量的包,我一般还是建议用外部工具解压,py7zr 更适合在需要增量拉取的脚本场景里用。
解压完先别急着跑,在目录里确认一下有没有主运行脚本(常见叫 acolite.py)和 README。不同小版本的入口脚本名可能有差异,以包内说明为准,后面所有命令行调用都以这个入口为基础。
3. 为什么 Acolite 做大气校正:原理拆解与 Sen2Cor、6S 的选型对比
3.1 大气校正到底在消除什么
L1C 影像存储的是传感器顶部的表观反射率,也就是 TOA 反射率。从 TOA 到水面遥感反射率 Rrs,中间隔着好几层东西:空气分子瑞利散射、气溶胶散射、臭氧和水汽吸收、水面反射的天空光,以及光在大气中来回透过时的衰减。陆地遥感里很多大气校正算法做到“地表反射率”就收手了,但水色遥感关心的是水面以下的离水辐亮度信号,最终要的是刚好在水面以下的遥感反射率 Rrs,单位是 sr⁻¹。
这两者之间差了一个水面反射校正和光场几何的转换量。所以把陆地产品直接拿来算水体参数,理论上就不对,实践上更是经常算出负值或异常峰。Acolite 存在的价值,就是专门把这个“大气 + 水面”的校正过程,针对水体场景做完整处理。
3.2 Acolite 的核心方法:SWIR 暗像元气溶胶估算与查找表插值
Acolite 的方法基础可以拆成三步理解。第一步,利用水体在近红外和短波红外波段几乎是黑的这一物理特性。以 Sentinel-2 为例,1610 nm 和 2190 nm 处清洁水体的离水信号接近于零,传感器在这两个波段收到的反射率,基本就是大气贡献本身。
第二步,用两个 SWIR 波段的比值去估算气溶胶的光谱衰减关系,也就是 Angstrom 指数,再把这个关系外推到可见光波段,逐像元估计出气溶胶反射率。第三步,用预先算好的辐射传输查找表 LUT,把大气透过率、漫射透过率、天空光等系数插值出来,最终把 TOA 反射率转成水面遥感反射率 Rrs。
这套流程最大的吸引力在于不需要输入地面能见度、气溶胶类型这类现场气象参数,全部信息都从影像自身提取。对历史影像做批量处理时,这个特性非常关键——你没有地方去补十年前每一景影像的现场能见度数据,但 Acolite 根本不需要。
3.3 为什么不用 Sen2Cor 和 6S:水色场景的选型理由
Sen2Cor 是哨兵二号官方 L2A 处理链路,目标是生成陆地地表反射率产品。它把水体当陆地场景做气溶胶估算,而水体在近红外波段是暗目标,Sen2Cor 的气溶胶反演在暗水面上很不稳定。我见过不少 L2A 产品在水库区域给出“像农田一样亮”的近红外假信号,还伴随条带。做水质反演的人拿到这种数据,还得先做掩膜和清洗,不如直接从 L1C 开始用 Acolite。
6S 和 MODTRAN 这类辐射传输模型的精度本身没问题,但操作成本太高。每次运行需要输入气溶胶类型、能见度、观测几何、波段响应函数,逐景逐波段配置,批处理前要塞一堆脚本参数。对没有现场气象资料的历史影像,能见度根本填不出来。6S 适合做单景验证或算法研究,不适合做批量生产。
下面这个对比表可以帮你快速决策:
| 维度 | Acolite | Sen2Cor | 6S |
|---|---|---|---|
| 输入数据 | L1C 目录或 MTL 文件 | L1C SAFE 目录 | 自备波段与观测几何 |
| 外部气象数据 | 不需要,影像自估算 | 不需要 | 需要能见度、气溶胶模式 |
| 主要输出 | Rrs、rho_t、RGB、GeoTIFF | 地表反射率 BOA | 逐波段地表反射率 |
| 水体适应性 | 专门为水色设计,整体稳定 | 差,水域经常出现假信号 | 精度可调,但输入要求高 |
| 批处理友好度 | 目录级输入,适合批量 | 批处理尚可 | 需要脚本封装,工作量大 |
3.4 场景适配检查:你的数据适不适合 Acolite
在决定投入时间之前,我会按下面这个清单过一遍自己的数据。第一,影像是不是 L1C 或 TOA 级别?L2A 直接送进去,结果基本是荒谬的。第二,场景里有没有清洁水体的深水区?Acolite 的气溶胶估算依赖 SWIR 暗像元假设,如果整景都是高浊度河口或泥沙滩,它会翻车。第三,区域里云阴影和山地阴影多不多?阴影区的大气路径辐射和正常区域不一样,结果容易偏负。第四,你的反演算法到底需要 Rrs 还是 rho_t?有些经验算法只认表观反射率,那 Acolite 的 rho_t 输出反而更合适。
这些问题想清楚后再动手,能省下后面大半的排错时间。
4. 跑通第一景大气校正:从 L1C 到 L2W 的最小命令与核心参数
4.1 准备输入数据:认识 L1C 的目录结构
Sentinel-2 L1C 的典型结构是 SAFE 格式目录,里面包含 GRANULE 子目录和 MTD_MSIL1C.xml 元数据文件;Landsat Collection 2 L1TP 则以 MTL 文本文件为中心,各波段是独立的 GeoTIFF。Acolite 直接以目录或 MTL 文件路径为输入,自动识别传感器和波段列表。
这里要反复强调:喂给 Acolite 的必须是 TOA 级别的 L1C 产品。如果你手上只有 L2A,不要试图转格式或改名,老老实实重新下载同景 L1C。另外下载后不要重命名 SAFE 目录,有些情况下元数据文件里的名称与目录名不一致,Acolite 识别传感器时就会出错。
4.2 Linux/macOS 命令行最小流程:一次调用跑出 L2W
Acolite 提供了命令行入口,最小运行命令是:
cd /path/to/acolite input=/data/s2/S2A_MSIL1C_xxx.SAFE output=/data/s2/out python acolite.py --cli \ --input="$input" \ --output="$output" \ --l2w_export_geotiff=True上面这段做了三件事:--cli告诉程序走命令行模式而不是弹 GUI;--input指向 L1C 的 SAFE 目录;--output指定输出根目录;--l2w_export_geotiff=True让程序导出 L2W 产品的 GeoTIFF,方便在 GIS 里直接查看。
不同小版本的启动脚本名可能不同,有的版本是acolite_cl.py,有的是acolite.py --cli,以包内 README 为准。第一次运行时控制台会输出大量日志,看到输出目录里出现 L2W 文件夹,就说明这一景跑通了。
跑通一次后,建议立刻把命令改成变量驱动的形式,为后面的批处理打基础:
python acolite.py --cli --input="$scene" --output="$out" --l2w_export_geotiff=True这样后续换场景只需要改两个变量。
4.3 Windows 下用 GUI 跑通:点选目录到导出 GeoTIFF
Windows 用户通常更习惯 GUI 操作。启动主界面后,选择对应的传感器入口,比如 Run Sentinel-2 或 Run Landsat,然后在输入框里选中 L1C 目录,设置输出目录,勾选 Export GeoTIFF,点运行按钮。
双击 acolite.py 没反应时,多数情况是 .py 文件被关联到了编辑器而不是 Python 解释器。解决办法是打开命令行,手动执行:
python acolite.pyGUI 模式的参数和命令行是同一个配置体系,里面对应的选项就是命令行的--l2w_export_geotiff、--mask_land这些。我的习惯是先在 GUI 里跑一次小影像,确认输出正常后再转到命令行做批处理,这样可以直观看到每一步中间产物。
4.4 核心参数表:哪些必调,哪些可以放着不管
Acolite 的参数很多,但常用的就几个。按我的使用频率排序:
| 参数 | 作用 | 我的建议 |
|---|---|---|
--l2w_export_geotiff | 输出 GeoTIFF 格式水体产品 | 默认开启,GIS 分析必需 |
--s2_target_res | Sentinel-2 输出分辨率 | 机器吃力时改 20 或 60,调参阶段够用 |
--threads | 并行线程数 | 批处理时限制并发,避免占满服务器 |
--mask_land | 陆地掩膜 | 近岸、水体破碎场景建议开启 |
--l2w_export_netcdf | 输出 netCDF 格式 | 需要逐像元连续变量时改为 True |
参数名在不同小版本里可能有细微差异,但语义基本一致。不确定时可以加--help查看当前版本的参数列表,这是最可靠的核对方式,不用死记。
4.5 输出文件怎么读:L2W 里的 Rrs 与辅助产品
处理完成后,输出目录下会生成 L2W 文件夹,里面是 Rrs 各波段的 GeoTIFF,以及 rho_t 产品、RGB 浏览图和处理日志。文件名通常包含 Rrs 和中心波长,比如 Rrs_665.tif 对应红光波段。
拿到 GeoTIFF 后,第一件事是目检。打开 RGB 浏览图,确认水体区域没有条纹、没有条带状异常,近岸可能存在少量负值,但不应成片出现。如果发现大面积负值或全黑影像,问题多半出在输入数据级别或路径上。
4.6 时间与资源预算:先小分辨率验证,再全分辨率生产
按照我的经验,Sentinel-2 一景 10 m 全分辨率处理,在 8 核 16 G 内存的笔记本上大约需要 20 到 40 分钟;Landsat 8/9 一景大约 5 到 10 分钟。时间主要花在高分辨率逐像元外插阶段,所以调参的时候不要直接跑全分辨率。
我一般先用--s2_target_res=60快速跑通一景,确认参数组合和输出正确,再切回 10 m 做正式处理。这个小习惯能省下大量试错时间。
5. Acolite 常见问题与避坑:解压失败、全黑、负值到浑浊水体的 5 条记录
5.1 7z 解压报 CRC 失败或“压缩包已损坏”
现象是7z x解压到一半报 CRC 错误,或者解压完明显缺文件。原因是下载文件不完整,网盘限速或断点续传异常导致的截断最常见。7z 是连续性压缩格式,末尾几 MB 的缺失就会让整个包损坏。
解决方法是重新下载,下载后先跑7z t acolite.7z确认完整,再解压。不要一遍遍重试同一个损坏的压缩包,这是白费时间。如果下载工具支持校验和,优先使用。
5.2 Python 环境装完依赖仍然 ImportError
现象是 numpy、scipy、matplotlib 都装好了,运行 acolite.py 时仍然报ModuleNotFoundError: gdal。原因是 GDAL 的 wheel 版本和 Python 版本不匹配,或者 conda 与 pip 混装导致两个环境互相看不见。
解决方法是不要在现有环境里硬补,直接新建一个干净的 conda 环境,指定 Python 3.9 左右,然后用 conda-forge 安装 GDAL:
conda create -n acolite python=3.9 conda activate acolite conda install -c conda-forge gdal numpy scipy matplotlib这是我踩过最深的坑。Python 3.11 以上在 Windows 上装 GDAL 尤其容易翻车,与其花一下午解决依赖冲突,不如一开始就建独立环境。
5.3 输出 Rrs 全黑或大面积极低
现象是处理了半小时,导出 GeoTIFF 几乎全黑,数值全部接近零。最常见原因是输入数据不是 L1C 而是 L2A,Acolite 拿到已经被陆地算法处理过的 BOA 产品,整个流程假设的前提就错了。
其次是路径含中文或空格,GDAL 读取元数据失败,导致区域识别错误。解决方法是先确认影像级别,再看路径。我会在输入之前打开 MTL 或 MTD 文件看一眼产品级别字段,这个习惯比跑完再看结果高效得多。
5.4 靠岸区域花斑与负值:陆地像元污染气溶胶估算
现象是水体边缘出现蓝色或红色的花斑,Rrs 出现成片负值,形状沿着岸线分布。原因是陆地像元进入了气溶胶估算的统计窗口,Acolite 把陆地的近红外反射当成大气信号的一部分,估算出的气溶胶被污染。
解决方法是开启陆地掩膜参数,让程序在估算气溶胶时排除陆地像元。水体像元在蓝波段出现轻微负值可以接受,但如果负值成片沿着岸线铺开,就一定要处理。另外,云阴影和山地阴影边界也容易出现类似现象,这类像元会在后续反演时拖低精度。
5.5 高浑浊水体结果离谱:SWIR 暗像元假设失效
现象是高悬浮泥沙河流的 Rrs 绿波段被明显低估,或者影像上出现规律的亮暗条纹。原因是水体在 SWIR 波段不再是暗像元,泥沙的散射贡献被 Acolite 误算成了气溶胶。
解决方法是不要在极端浑浊场景强行使用默认流程。可以改用 rho_t 输出自己做经验校正,或者手动限定气溶胶估算区域到深水区,再或者直接承认 Acolite 不适合这类场景。它适合的是清洁水体和中等浑浊度水体,不是灵丹妙药,这一点要先认清。
6. 进阶:验证 Rrs 结果并接进批量水色反演流程
6.1 结果验证:谱形检查与实测站点对比
Rrs 是反演模型的输入,输出不能直接信。最朴素的验证方法是用 rasterio 读两个波段,算归一化差值,看数值范围是否符合这类水体的经验区间:
import rasterio import numpy as np red = rasterio.open(".../L2W/Rrs_665.tif").read(1).astype(float) blue = rasterio.open(".../L2W/Rrs_492.tif").read(1).astype(float) # 用有效像元计算归一化差值 valid = (red > 0) & (blue > 0) nd = (red[valid] - blue[valid]) / (red[valid] + blue[valid]) print(np.nanpercentile(nd, [5, 50, 95]))如果中位数偏离经验范围太远,就要回头检查参数配置。更严格的验证是找 AERONET-OC 水色站点的实测 Rrs 做时间匹配,计算 RMSE。没有实测数据时,谱形目检至少能挡住八成明显错误。
6.2 批量处理与日志复盘:让一百景影像跑完不翻车
批处理的核心是日志。逐景跑完再去检索失败原因,会浪费大量时间。我一般会把每景的日志重定向到独立文件,跑完后统一 grep 关键词:
for scene in /data/s2/*.SAFE; do name=$(basename "$scene") echo "=== $name ===" python acolite.py --cli \ --input="$scene" \ --output=/data/out \ --l2w_export_geotiff=True \ > /data/logs/"$name".log 2>&1 done跑完后检查输出目录里是否每个场景都生成了 L2W 文件夹,再抽查 10% 的输出影像做目检。抽检时我最关注的是坐标系是否正确,处理后的 GeoTIFF 是否落在原始 UTM 带上。
有一次我批量跑了三个月的四十景影像,第三个月做验证时才发现坐标偏移了一公里,原因是初始影像跨了两个 UTM 带,批处理脚本没有强制输出坐标系。从那以后,我每次都从 L2W 输出里读一次地理范围做冒烟测试,验证步骤再繁琐也比返工轻松。希望帮到你。
本文还有配套的精品资源,点击获取