Depth Anything 3 实操:从单张卫星图生成深度 GeoTIFF
一句话结论:不用建筑多边形、DEM、相机外参,一张 RGB 卫星影像就能跑出深度图。日本 OrbitalNet 团队用 Depth Anything 3(DA3MONO-LARGE) 做单目相对深度估计,把结果写回与输入同网格的 GeoTIFF;对建筑边界,他们用 300 像素分块 + 100 像素重叠 + shift 对齐融合,目视锐度明显好于整图下采样推理。但要先记住三件事:输出是相对深度、显示图不是建筑高度、目视对比不是精度验证。
LAS 点云在线查看器
本文完整编译 dev.to 文章《Creating Depth GeoTIFFs from Satellite and Aerial Imagery with Depth Anything 3》(2026-10-13,作者 lehua555 / OrbitalNet),并做中文整理。
一、这个流程能做什么、不能做什么
- 能:从单张卫星/航拍影像得到相对深度;论文式说明与后续工作见 OrbitalNet 的"卫星建筑 3D"介绍页。论文作者的原话是:从单张卫星图估计的深度,可以生成几何上与 LOD2 相当的建筑模型。
- 不能:输出不直接给出米制建筑高度、DSM 或 DEM。生成 3D 建筑、以及把建筑放到 DEM 上,都是独立的后续步骤。
- 不使用:建筑多边形、DEM、相机外参(exterior orientation)都不是输入。
示例用的是 WorldView-2 归档影像(50 cm 分辨率);因为压缩噪声让建筑边界不清,他们先做了 2× 超分与图像增强。
二、模型与处理流水线
用的是 depth-anything/DA3MONO-LARGE——官方模型卡定义为单目相对深度估计模型,与 DA3-LARGE、DA3METRIC-LARGE 不是同一个模型。
读 RGB GeoTIFF → DA3 推理 → 把深度预测缩回原始像素网格 → 存 GeoTIFF
分块版在此基础上:先切块 → 逐块推理 → 融合各块深度 → 再保存。注意:DA3 用的是官方 API;GeoTIFF 读写与分块融合是这篇文章附带的脚本实现的,不是 DA3 官方的地理分块推理功能。
三、环境:先把版本组合钉死
| 项目 | 配置 |
|---|---|
| 操作系统 | Ubuntu 24.04 |
| GPU | NVIDIA RTX PRO 6000 Blackwell Max-Q |
| Python | 3.10 / 独立 conda 环境 |
| PyTorch | 2.9.1,CUDA 12.8 wheel |
| torchvision | 0.24.1 |
| xFormers | 0.0.33.post2 |
| NumPy | 1.26.4 |
| OpenCV | opencv-python 4.10.0.84 |
| MoviePy | 1.0.3 |
| 模型 | DA3MONO-LARGE |
| GeoTIFF 读写 | Rasterio |
作者明确说:这块 GPU 的显存不是流程要求,显存需求取决于输入分辨率与环境;本文不评估其它 GPU 的最低显存与速度。另外提醒:nvidia-smi 显示的 CUDA Version、nvcc --version 显示的 Toolkit 版本、torch.version.cuda 显示的 PyTorch 版本含义不同;本文用的是 CUDA 12.8 的 PyTorch wheel,不替换系统 CUDA Toolkit,需要事先装好 NVIDIA 驱动。
四、建目录、装依赖、下载权重
conda create -n da3_bw python=3.10 pip -y
conda activate da3_bw
mkdir -p ~/da3_geotiff/input ~/da3_geotiff/output ~/da3_geotiff/logs
cd ~/da3_geotiff
把原文附录里的 7 个脚本保存到 ~/da3_geotiff/:constraints.txt(钉版本)、setup.sh、check_env.py、download_model.py、infer_geotiff.py、da3_tile_io.py、infer_geotiff_tiled.py。然后:
bash setup.sh
setup.sh 会:① 安装 CUDA 12.8 版 PyTorch/torchvision/xFormers;② 把官方仓库 clone 到 vendor/Depth-Anything-3;③ 装 DA3 基础依赖与 Rasterio 等;④ 跑 pip check、import 检查与 CUDA 矩阵乘测试;⑤ 把 Git commit ID 与 pip freeze 存进 logs/。
注意:只装基础依赖,Gradio 与 3D Gaussian 输出的可选组件不装,推理用 infer_gs=False。检查环境:
python -m pip check
python check_env.py # 应包含 CUDA runtime: 12.8、GPU 型号、Imports and CUDA matrix multiplication: OK
作者提醒:pin 了主包,但这不是全量锁定的环境;将来遇到依赖冲突,先看错误日志与下载的 commit,再决定是否放开 constraints。
下载权重:
python download_model.py
cat models/DA3MONO-LARGE/download_revision.txt
脚本会从 Hugging Face 官方仓库解析并下载特定 revision,把 revision ID 记录下来;推理只加载本地权重,不上传输入影像。
五、输入要求:uint8 的 8 位 RGB
- 8 位
uint8的 RGB 源图; - 带 CRS 与仿射变换的 GeoTIFF;
- 默认用 1/2/3 波段作 R/G/B;顺序不同要加
--bands(例如--bands 3 2 1); - 不能把已有深度/高程图当输入。
16 位卫星影像要先统一转成 8 位 RGB:全图用同一种方法,避免简单 astype(uint8) 或逐块独立调对比度。脚本遇到 16 位影像会直接停下,不会自动转换。
第 4 个波段不传给模型;Rasterio 识别的 alpha / NoData 掩膜用来确定有效像素——缺失像素推理时用 RGB 中位数填充,输出时还原为 NoData,但这不能消除缺失区域对周边预测的影响。
六、整图推理:先看全貌
长任务用 tmux。命令:
python -u infer_geotiff.py \
--input input/area_rgb.tif \
--output-prefix output/area_da3_full_r1008 \
--process-res 1008 \
2>&1 | tee logs/area_da3_full_r1008.log
理解 --process-res 1008:它是送给模型的最长边近似尺寸,不是把原图切成 1008 像素的块。预处理会不裁剪地缩放到合适的 patch 尺寸。输出深度再用双线性插值缩回原图尺寸——所以输入输出像素尺寸一致,不代表缩放推理中丢掉的细节被找回来了。
作者观察到:整图推理时预测的建筑边界发糊,可能是整图被内部下采样所致。
七、分块推理:300 + 100 + 518 + shift
改用原图上的小块推理:
python -u infer_geotiff_tiled.py \
--input input/area_rgb.tif \
--output-prefix output/area_da3_t300_o100_r518_shift \
--tile-size 300 --overlap 100 \
--process-res 518 --alignment shift \
2>&1 | tee logs/area_da3_t300_o100_r518_shift.log
| 参数 | 含义 |
|---|---|
--tile-size 300 |
原图上裁剪尺寸,通常 300×300 |
--overlap 100 |
相邻块重叠像素,步长因此为 200 |
--process-res 518 |
把 300 像素块送给模型时放大到的输入尺寸(必须是 14 的倍数) |
--alignment shift |
只用重叠区的深度差校正偏移 |
--output-prefix |
输出文件前缀 |
几个要点:
- 518 是 14 的倍数,包装脚本要求
process-res为 14 的倍数; - 把 300 像素放大到 518 只是模型输入准备,不提升影像的真实地面分辨率;
- 同样 300 像素,在 0.25 m/px 时覆盖 75×75 m,在 0.5 m/px 时覆盖 150×150 m——建筑与周边环境的占比不同,不能保证其它区域/分辨率下有同等精度;
- 图像边界处裁剪位置会回退以保持在图内,实际重叠可能超过 100 像素;宽或高不足 300 像素时用边缘像素填充。2048×1955 的示例图产生 10×10 = 100 块;
- 模型只在开头加载一次,块按顺序处理,每块预测缩回 300 网格后融合进镶嵌图。
三种融合模式
| 模式 | 校正内容 | 特点 |
|---|---|---|
shift |
仅偏移 | 不改变块内深度差的比例 |
affine |
缩放 + 偏移 | 对齐重叠区尺度,但也会改变局部起伏的幅度 |
none |
不做数值校正 | 直接加权平均,块间差异可能残留 |
本文为比较建筑细节,显式选择 shift:提供的代码默认是 affine,这个参数不能省。shift 的偏移量取重叠区有效像素的中位数差(b = median(m − d),d' = d + b);第一块或无有效重叠时偏移为 0。融合用向块中心加权的加权平均。
这里说清:"对齐"不是几何变换,只是把同一像素位置上预测的深度参考水平对齐;分块没有各自 0–1 归一化后再融合;shift 也无法解决真正的尺度差异——仍可能残留与扫描顺序相关的误差累积、以及重叠区平均带来的模糊。
八、输出文件怎么读
| 后缀 | 内容 | 用途 |
|---|---|---|
_depth.tif |
Float32 相对深度,越大越远 | 数值分析与下游处理 |
_near01.tif |
归一化到 0–1 的显示用 GeoTIFF,越近越接近 1 | 在 QGIS 里目视检查 |
_near.png |
同样表示的 8 位 PNG | 图像对比 / 文章配图 |
_metadata.json |
推理设置、GPU、图像尺寸、分块校正等 | 核查运行条件 |
GeoTIFF 输出保留输入的 CRS、仿射变换、宽高;NoData 是 -9999。无效像素位置保留,但任意 TIFF 标签与原 NoData 值不会全部原样复制。分块版的 _depth.tif 是融合校正后的相对深度,不是各块未校正的预测;shift/affine 校正可能产生负值。
关键警告:near01 不是建筑高度
显示图用的是相对全图有效深度值的第 1 与第 99 百分位做线性拉伸与反向:
N = clip((P99 − D) / (P99 − P1), 0, 1)
所以它是对比度调整 + 深度方向线性反转,不是逆深度 1/D,也不是米制高度。而且每张图的显示范围是独立算的——不同区域的 near01 里,同样亮度不代表同样深度/高度。做数值处理请用 _depth.tif。
九、在 QGIS 里检查
- 载入原始 RGB GeoTIFF 与
_near01.tif; _near01.tif用 Singleband gray 显示;- 最小 0、最大 1,色带黑→白;
- 在相同位置与比例下,检查建筑边界、屋脊、屋面与道路的关系。
显示 _depth.tif 时按实际值域拉伸;固定 0–1 会让大量像素显示为纯白或纯黑——白色图片本身不能证明推理失败。
脚本还提供坐标与数值自检:src.crs == dst.crs、仿射变换一致、宽高一致、有效像素位置一致(src_valid == ~mask)、值有限,并打印 NoData 与 min/median/max。作者提醒:这些检查验证的是定位与格式,不评估深度精度。
示例结果与误读风险
输入是 2× 超分后的 WorldView-2 归档影像;输出里建筑与周边地面、部分屋面起伏表现为亮度变化,但整幅图也有大范围亮度变化——可能来自地形效应、估计误差或分块融合,单看这张图无法区分。因此:不要把屋面亮度直接当成建筑高度;相对地面的差异必须与实测值分别核对。
十、常见问题速查
| 症状 | 检查与处理 |
|---|---|
CUDA GPU required / 检测不到 CUDA |
查 nvidia-smi、check_env.py、当前 conda 环境 |
| CUDA 显存不足 | 降整图推理的 process-res,或改分块推理;分块时对比 518 与 392 等其它 14 的倍数 |
| xFormers 版本不匹配 | 检查 PyTorch/xFormers 组合,不要只升级其中之一 |
另外:换区域要改输入路径与输出名,不会复用上一区域结果;脚本禁止覆盖已有输出,重跑要换 --output-prefix;不支持中断续跑。
十一、工程视角的三条结论
- 这是一个可靠的第一步,不是完整管线。它把"单图 → 相对深度"做成了可复现的脚本;到"米制高度 / DSM / 建筑模型"之间,还有高程基准、尺度恢复与建模等步骤。
- 分块融合是效果与代价的取舍。tiling 能让建筑边界更锐利,但引入对齐假设与扫描顺序误差;
shift保留了局部起伏幅度,affine对齐尺度却会改动起伏——先想清楚你要哪种。 - 目视对比不等于验证。作者明确说这是视觉比较,不是对建筑高度或屋脊坡度做实测验证——把它当探索工具,不当测量工具。
来源
- dev.to / OrbitalNet, Creating Depth GeoTIFFs from Satellite and Aerial Imagery with Depth Anything 3(2026-10-13):https://dev.to/lehua555/creating-depth-geotiffs-from-satellite-and-aerial-imagery-with-depth-anything-3-from-environment-4361
- Depth Anything 3 官方仓库:https://github.com/ByteDance-Seed/Depth-Anything-3
- DA3MONO-LARGE 模型卡:https://huggingface.co/depth-anything/DA3MONO-LARGE
同主题阅读
- RTK vs PPK:无人机测绘怎么选
- Shapefile 与 GeoJSON:用 MapJS 在线预览 GIS 数据
- OpenDRIVE (xodr) 地图指南
- 专题:点云 / 3D 扫描 / 感知完全指南
本文由 BimAnt 编译整理,转载请注明出处。
本文属于「点云 / 3D 扫描」专题。查看专题全部文章 →