0. 先说结论
这个项目最初的目标很直接:把无人机原始照片喂进去,直接产出一张可浏览的正射 TDOM(True Digital Ortho Map)。框架借的是 Tortho-Gaussian,先做曲线展馆,再做低层村落。结果不漂亮:展馆在 3k 迭代后测试集全面退化,7k 时 TDOM 出现大片孔洞;村落在 3k 见顶,7k 掉到 20.26 dB。
但这次不漂亮的结果,最后收敛出一条比 PSNR 更有用的判断:
在小样本、固定正射产品视角下,3DGS 的失败通常不是训练不足,而是自由度超出了观测能偿付的范围。3k 是这本账的破产点。
我把它叫作"可观测性预算"。它不是新算法,而是一个审计顺序:先查真实观测,再查几何证据,再查高斯表示的自由度,最后才查渲染和产品语义。按这个顺序,我把两个场景、2×2 因子实验、一次被代码推翻的归因、以及 70.6% 零视锥覆盖的诊断串成了一条证据链。
这篇文章不卖"生产级 TDOM"。它只回答三个小问题:
- 为什么小样本 3DGS 会在 3k 后越训越差?
- 孔洞到底该怪谁:球谐、opacity reset,还是尺度剪枝?
- 如果你也在做固定视角的正射产品,哪些自由度可以删,哪些观测必须先补?
三条能直接拿走的结论:
- 3k 先停:不要默认 30k;先同时看 test PSNR、TDOM 覆盖和各向异性。训练 PSNR 还在涨,不代表产品在变好。
- 孔洞先查剪枝和掩膜 :3000 后的
size_threshold=20与被掩膜排除的覆盖相机,比 SH 阶数更值得先查。 - 三本账分开算:覆盖、形状、辐射各有各的干预;在 70% 网格零覆盖时,加正则/加先验是负资产。
1. 两个样本,和一张固定的产品视角
先说数据。两个样本都不是"大场景",而是小样本可行性验证。
| 项目 | A 曲线展馆 | B 低层村落 |
|---|---|---|
| 原始影像 | 5744 张,6000×4000,21.4 GB,无 EXIF/GPS | 392 张,5472×3648,3.4 GB,带 GPS |
| 实际使用 | 41 个种子 → 123 张,5 个相机组 | 100 张核心子集,3 个航次 |
| 稀疏重建 | 123/123 配准,0.545 px,118,946 点 | 100/100 配准,0.888 px,102,223 点 |
| 3k 测试 PSNR | 16.22 dB,TDOM 覆盖 100% | 24.22 dB,TDOM 覆盖 100% |
| 7k 测试 PSNR | 15.52 dB,TDOM 覆盖 62.2% | 20.26 dB,TDOM 覆盖 69.0% |
| 主要难点 | 曲线屋面、玻璃幕墙、弱纹理、强反射 | 低层建筑、道路、农田,纹理足但边界杂 |
这两个样本的差别,不是简单的"难/易"。展馆是光度可观测性 差:曲面和玻璃把同一个表面在不同视角下变成不同的颜色,固定方向的正射产品很难"偿付"这种方向自由度。村落是几何可观测性更友好:屋顶、道路、院子、农田都是哑光、有纹理、近似平面,同样的 3DGS 在 3k 就能到 24.22 dB。
TDOM 的产品形态是固定正射方向、可浏览的影像;它不是自由视角 3DGS。这里还有一个容易被忽略的设定:训练用透视相机,产品是正交 TDOM。训练时模型看到的是多方向透视视图,输出时只取一个正交方向。这个"训练视角"和"产品视角"的错位,是后面所有自由度问题的源头。
项目中途我整理了 23 份资料:知识组 11 份/92 页,技术专题 6 份/52 页,增强组 6 份/40 页。它们没有变成"方法堆叠"。我先建立五层证据链,再把每份资料的主张放回它对应的层。结果很直接:多数方法在几何证据/高斯优化/可见性渲染层加能力,而我的瓶颈在最前面的"观测"层。在观测不足时,继续加方法不是增益,是 confounding。

2. 可观测性预算:一个审计顺序,不是新算法
我先把"预算"拆成三个可操作的概念:
- 预算:观测能提供的独立约束。包括视角数、交会角、纹理、非反射表面、有效掩膜、真实覆盖。
- 支出:表示的自由度。包括高斯数量、各向异性、不透明度变化、球谐方向维数。
- 破产:训练损失还在下降,但测试辐射质量、覆盖或几何稳定性同时恶化。
它不是一个可以直接计算的物理量,而是一个审计顺序。顺序错了,就会把"观测不足"误判成"模型不够强",然后不断加正则、加先验、加训练时长。
| 层 | 要回答的问题 | 本项目怎么查 | 本项目看到什么 |
|---|---|---|---|
| 1 观测 | 真实影像是否真的看到目标区域? | 7048 个网格、z=4 平面的视锥覆盖、掩膜排除 | 70.64% 网格零相机;12 台覆盖相机被掩膜排除 |
| 2 几何证据 | 轨迹和位姿是否可靠? | 8055 个缺失区稀疏点、支持相机、交会角、残差 | 66.15% 可靠、30.50% 待复核、3.35% 孤立;中位误差 0.347 px |
| 3 高斯优化 | 表示是否用了过多自由度? | 各向异性>10 比例、尺度分布、不透明度 | 未正则组 3k→7k 约 1.1--1.2%→8.0--8.2%;尺度正则压到 0.064%,但不修孔洞 |
| 4 可见性渲染 | 正确表面是否按正确顺序合成? | 视角微扰、排序稳定性、Alpha 覆盖 | ±0.1° 无全局 popping;局部排序仍未排除 |
| 5 产品证据 | 哪些是测量、推断、未知? | Alpha、NoData、Q_all/Q_valid 双分母 | Alpha 是累积不透明度,不是观测置信度 |
这张表最重要的作用,是阻止"方法堆叠"。如果第 1 层是零覆盖,第 3/4 层的正则、排序、生成先验都不会把观测变出来。在观测不足时,方法叠加是负资产。
3. 3k 悬崖:训练损失还在降,测试集已经转身
先读表说明:本文所有数字都带协议。P3 是 llffhold=83 的两视角 holdout;P4 是 13 视角交错 holdout;2×2 是 116 视角/11 个固定 holdout;村落是独立样本。不同协议之间的绝对值不能直接相减,我只在同一协议内做因果比较。
| 场景 | 3k test | 7k test | 3k train | 7k train | 3k 覆盖 | 7k 覆盖 |
|---|---|---|---|---|---|---|
| A 曲线展馆(P4 E0) | 16.216 dB | 15.522 dB | 19.86 dB | 21.61 dB | 100% | 62.19% |
| B 低层村落 | 24.225 dB | 20.258 dB | 25.53 dB | 28.78 dB | 100% | 69.00% |
这张表里最值得看的是两列 train 和两列 test 的反向运动:训练 PSNR 从 19.86 涨到 21.61,测试 PSNR 从 16.22 掉到 15.52;村落的训练 PSNR 从 25.53 涨到 28.78,测试从 24.22 掉到 20.26。与此同时,展馆 TDOM 的非空覆盖从 100% 掉到 62.19%,村落从 100% 掉到 69.00%。

这不是"训练日程没调好"。3k 附近恰好是这套代码启用尺度剪枝的时间点:size_threshold=20 在 3000 后生效。从日志和代码路径看,3k 是尺度剪枝启用前的最后一个完整检查点。后面会看到,剪枝删掉的不只是"冗余大高斯",还包括支撑覆盖的必要大高斯。
所以"3k 悬崖"有两个层面:
- 统计层面:测试集过拟合,训练损失继续下降,泛化指标转身。
- 机制层面:尺度剪枝开始删除大高斯,覆盖和几何稳定性同时受损。
只看到第一层,会得出"早停"的结论;看到第二层,才会去改剪枝策略、补观测,而不是盲目加到 30k。
4. 2×2 因子实验:覆盖、形状、辐射是三本账
为了把"剪枝"和"尺度正则"分开,我做了 2×2 因子实验:
- 数据集:116 视角,11 个固定 holdout,7 个获批的 A 组恢复视角。
- 因子:是否启用尺度剪枝 × 是否启用尺度正则。
- 终点:7k;同时回看 3k 检查点。
| 组 | 剪枝 | 尺度正则 | 3k PSNR | 7k PSNR | 7k 覆盖 | 7k 各向异性>10 |
|---|---|---|---|---|---|---|
| A | 是 | 否 | 17.785 | 16.815 | 83.21% | 8.21% |
| B | 否 | 否 | 17.821 | 16.963 | 100% | 8.00% |
| C | 是 | 是 | 17.978 | 16.696 | 81.53% | 0.064% |
| D | 否 | 是 | 17.698 | 16.844 | 100% | 0.068% |
主效应很清楚:
- 关剪枝:7k PSNR +0.148 dB,覆盖从 83.21% 回到 100%;代价是边缘更糊、锐度下降。
- 尺度正则 :各向异性>10 从 8.21% 压到 0.064%,但 7k PSNR −0.119 dB;它不修孔洞,覆盖仍只有 81.53%。
- 交互项:−0.0003 dB,约等于 0。覆盖和形状是两本独立的账,不能指望一个开关同时解决。

这里有两个读表细节,值得单独说:
- 3k 的数字早于 3100 的尺度正则启动。C 组 3k 的 17.978 不能记在尺度正则头上;3k 的公平比较是 A/B/C/D 的 17.7--18.0 平台。真正能归因于尺度正则的是 7k 的各向异性比例,而不是 3k 的 PSNR。
- E1 和 B 组都叫"不剪枝",但不能直接合并。E1 是 123 视角/13 holdout,B 是 116 视角/11 holdout;而且 E1 在 3k 就已经比 E0 低 0.27 dB,说明"不剪枝"本身也改变了优化动力学,不能把 E1 的 7k 差异简单归因于剪枝。B 组才是同一 116 视角协议内的干净比较:不剪枝 +0.148 dB、覆盖 83.21%→100%。这也是我坚持用 2×2 固定协议的原因。
5. 一次被代码推翻的归因:不是 opacity reset
项目早期,我对 7k 孔洞的解释是"3000 迭代时 opacity reset 把高斯删了"。这个解释听起来很合理,因为很多 3DGS 实现确实有这个机制。但它错了。
我把训练路径的代码逐行对了一遍:
text
train.py:128-130
opacity_reset_interval 只参与 size_threshold=20 的选择
scene/gaussian_model.py:526-529
max_radii2D > 20 或 max scale > 0.1 * camera_extent 时删除
scene/gaussian_model.py:521
min_opacity = -1e14,opacity prune 的比较实际失效
train_vast.py:152-153
reset_opacity_features 只在这里出现,不在 E0/E1/E2/B1 的 train.py 路径
修正后的机制是:
3000 后启用的是基于尺度的剪枝,不是 opacity reset。必要的大高斯被删掉,剩下的小而长的高斯继续增密。结果是孔洞 + 各向异性上升,同时训练损失还在下降。
这个纠正很重要,因为错误的标签会导致错误的干预:
- 如果相信"opacity reset",你会去关 reset,或者调 opacity。
- 如果相信"尺度剪枝",你会去分离
size_threshold和尺度正则,或者补覆盖观测。 - 这两条路的代价完全不同。
这也是我认为这篇文章最"工程"的部分:归因不是写日志,是要回到代码路径。一个听起来顺耳的解释,如果没有代码证据,很容易把后续实验带偏。
6. 缺失区诊断:缺的是观测,不是高斯
7k 的孔洞到底是不是"点云空了"?我做了缺失区诊断:在 z=4 的主平面上铺 7048 个网格,统计每个网格被多少台注册相机看到。
结果:
- 70.64% 的网格零相机覆盖。
Q_all(以全部网格为分母)中,至少 3 台相机覆盖的比例只有 20.81%。Q_valid(以"至少 1 台相机覆盖"的网格为分母)中,至少 3 台相机覆盖的比例是 70.90%。- 12 台注册相机其实覆盖缺失区,但被语义掩膜排除了:A 组 7 台、S 组 1 台、X 组 4 台。
- 缺失区里有 8055 个稀疏点:66.15% 可靠、30.50% 待复核、3.35% 孤立;中位重投影误差 0.347 px;97.63% 至少有一个 B1 观测。

这组数字说明两件事:
- 缺失区不是空点云,也不是整体浮空。它有一批可靠的轨迹和点,问题在于相机使用和掩膜排除,而不是"高斯不够多"。
- Alpha 覆盖会骗人。TDOM 的非空像素可以到 100%,但那只是累积不透明度,不是"这个像素被真实观测过"。这两个指标必须分开报。
这也是"可观测性预算"的最强证据:当 70.64% 的网格零相机时,继续加高斯、加迭代、加正则,都是在给一个没有观测的区域记假账。
7. SH0 的减法红利,和它的边界
在表示层面,我做了一个反直觉的尝试:把球谐从 SH3 降到 SH0。
| 实验 | 3k test | 7k test | 运行时间 | 7k 覆盖 |
|---|---|---|---|---|
| E0:SH3 + 剪枝 | 16.216 dB | 15.522 dB | 1625 s | 62.19% |
| E2:SH0 + 剪枝 | 16.206 dB | 15.888 dB | 1515 s | 61.84% |
3k 基本打平(16.206 vs 16.216),7k 反而高 0.366 dB,运行时间少 110 秒。但 SH0 没有修掉孔洞:7k 覆盖仍然是 61.84%。这说明方向自由度不是孔洞的根因,孔洞的根因还是尺度剪枝和观测不足。
这个实验的边界必须说清楚:E2 是"颜色+不透明度"的 FAGK(球谐参数化)打包消融,不是只改 SH 的干净单变量实验;而且是单次运行。它只能算假设生成级证据,不能写成"SH0 一定更好"。
但它背后的理论值得记下来:
固定正交方向下,完整的方向颜色/不透明度函数是不可辨识的;高阶 SH 不是被恢复出来的物理 BRDF。对一个只输出单一方向的正射产品,方向维度的自由度没有被产品偿付。
这句话是本文最"反潮流"的地方。很多工作默认 SH3 更强,但在固定正射产品里,SH3 的额外自由度可能只是在拟合训练视角,而不是在描述表面。SH0 是一个值得验证的减法,不是 universal winner。
8. 产品边界:GeoTIFF 不是"一张图"
最后落到产品。当前输出是局部北向的 RGBA GeoTIFF,1600×1000,Alpha 作为 NoData。展馆的局部单位/像素约 0.0188,村落约 0.0180。它没有 EPSG,没有绝对尺度,也没有 POS/GCP 支撑。

我坚持把边界写进产品,而不是藏在 README 里:
- 坐标系:局部任意 COLMAP 坐标,无 EPSG、无绝对尺度。
- Alpha:累积高斯不透明度,NoData 语义;不是观测置信度。
- 评估:Q_all 与 Q_valid 双分母;覆盖、几何、完整、重复性四轴分开报。
- 重复性:没有做独立 A/B 子集重建,所以不声明 repeatability。
- 精度:没有 GCP/POS,不声明测绘级精度;13 视角 holdout 只是探索性泛化评估,不是独立空间精度评估。
这些边界不是"免责声明",而是产品的一部分。把"测量、推断、未知"分开,别人才敢复用你的结果。
工程实现上,这套流水线是 Docker CUDA 11.8 + 双 venv(透视训练/正交渲染,同名 CUDA 扩展必须隔离)+ 25 个 Python 脚本 + 6 个回归测试;上游 commit 用 SHA256 锁定。双 venv 不是洁癖:同名扩展混用会静默加载错的 rasterizer,表现为黑图或尺度异常。
9. 如果你也要做:一页纸止损清单
| 症状 | 先查什么 | 不要做什么 |
|---|---|---|
| 3k 后 test PSNR 下降、train 上升 | 是否过拟合;coverage 是否同时下降 | 不要直接加到 30k |
| TDOM 出现孔洞 | 3000 后 size_threshold=20 是否启用;覆盖相机是否被掩膜排除 |
不要先怪 SH 或 opacity reset |
| 各向异性>10 比例上升 | 尺度正则是否开启;代价是否可接受 | 不要指望尺度正则修孔洞 |
| 覆盖不足 | 视锥覆盖、≥3 相机支持、掩膜 | 不要用 Alpha 当观测完整度 |
| 边缘模糊 | 是否关剪枝;是否尺度正则 | 不要用"更久训练"换清晰度 |
| 固定正射产品 | SH 阶数、方向自由度 | 不要默认 SH3 一定更好 |
| 小样本配准差 | 种子连通性、相邻帧、跨航线边 | 不要先降匹配阈值 |
| 想上生产 | GCP/POS、独立检查点、重复性 | 不要拿单次运行当精度报告 |
如果只能记一条:先补观测,再减自由度,最后才加方法。
10. 边界与下一步
这篇文章的结论有明确的边界:
- 两个样本都是小样本,不能外推到大规模城市级重建。
- 展馆与村落是不同协议,绝对值不可直接比较;2×2 只在 116 视角/11 holdout 内做因果比较。
- E2 的 SH0 是打包消融、单次运行,属于假设生成,不是定论。
- 没有独立 A/B 重复性重建,没有绝对地理精度,没有测绘级结论。
- 23 份资料是二手主题报告,正文的引用优先回到一手论文与官方仓库。
下一步我会做四件事:
- 用交错 A/B 子集做独立重复性重建,补上 repeatability 这一轴。
- 在可信轨迹上做小规模 joint BA,把几何证据层和高斯优化层分开。
- 对缺失区做 per-ray 排序/深度诊断,区分"没观测""没高斯""排序错"。
- 如果目标是测绘级产品,先上 GCP/POS,再谈绝对精度;否则就守住局部产品的边界。
这套框架是可证伪的:如果补了覆盖视角,覆盖和 PSNR 仍然不涨;或者 SH0 在第二个场景上明显更差;或者 2×2 的结论在独立重复中消失------那"可观测性预算"就需要修正。至少现在,它能解释我手上的全部证据,并且给出了下一步实验的优先级。
11. 结语:失败不是资产,可复用的失败才是
这个项目没有跑出一个生产级 TDOM,但它跑出了一条止损线:
先算观测账,再谈模型容量;先分开覆盖、形状、辐射,再谈调参;先回到代码路径,再给现象起名字。
如果你也在做小样本无人机 3DGS、正射 TDOM、或者任何"训练用透视、产品用固定视角"的重建任务,希望这套审计顺序能帮你少走一段弯路。
参考资料
只列一手论文/官方仓库;项目整理的 23 份二手主题资料不单独列,避免把二手总结当一手证据。
- Kerbl, B., et al. 3D Gaussian Splatting for Real-Time Radiance Field Rendering. SIGGRAPH 2023. arXiv:2308.04079.
- Tortho-Gaussian. arXiv:2411.19594. DOI: 10.1080/10095020.2026.2622788.
- REUrbanGS. arXiv:2507.23006.
- GloSplat. arXiv:2603.04847.
- SparseSplat. arXiv:2604.03069. CVPR 2026.
- SalientGS. arXiv:2607.11285.
- VoxelTTO. arXiv:2609.21498.
- CalibAnyView. arXiv:2605.14615.
- GSM-GS. arXiv:2602.12796.
- FilterGS. arXiv:2603.23891.
数据与复现
- 代码、配置、结果 JSON 与图:
https://atomgit.com/lucia-lee-geo/tdom-observability-budget(发布前确认仓库可访问)。 - 原始影像不公开:展馆 21.4 GB、村落 3.4 GB,含场地信息;仓库只保留脚本、配置、结果和小样本说明。
- 结果图来自项目输出;合成图与封面由脚本排版,发布前已剥离 EXIF;村落位置在文中做脱敏处理。
- 关键结果文件:
p2_validation.json、p3_validation.json、p4_validation.json、factorial_validation.json、four_axis_baseline.json、train_event_audit.json、missing_region_summary.json、village_validation.json。
作者:LUCIA LEE(李镜馨)|空间数据 × 实体行业 · 智能化技术栈
写作说明:本文的框架与文字经 AI 辅助整理,实验数据、代码审计与结论由作者复核;文中所有数字可在仓库
results/中复算。