卫星影像三维重建这个方向,这几年越来越热,但真正落到工程上,坑远比想象的多。我最早接触这个领域时,手里拿到的是一批亚米级商业卫星影像,外加一堆 RPC 文件,目标是把几十平方公里的城区做成带纹理的三维网格。当时第一反应是找现成的开源方案,试过几套主流的近景三维重建工具,结果在城市高楼和弱纹理区域上翻车得比较彻底。后来才转向 Danesfield 这套面向卫星影像的开源三维重建软件,用下来它在“大范围、长焦、小基高比”这类场景里确实比通用工具顺手得多。这篇就把我从环境编译、数据整理到跑通全流程、调参排错的经验完整摊开,适合已经在做 DSM、点云或者正射成果、想补上三维重建这一环的遥感与测绘方向同行,也适合做算法想复现卫星多视立体流程的同学。读完之后你应该能自己搭起一套可跑的环境,知道每个环节在干什么,以及遇到报错时往哪儿找。
1. 为什么选 Danesfield:卫星影像三维重建的方案选型逻辑
1.1 卫星影像和近景摄影测量根本不是一回事
很多人刚上手时会默认“三维重建工具不都差不多”,拿近景或无人机那套流程直接套卫星影像,结果第一步就卡住。这两类数据的成像几何差异是根本性的。近景和无人机通常是面阵相机、短焦距、大倾角、重叠度高,相邻影像之间的基线相对景深很大,视差充足,三角交会的几何条件很好。卫星影像走的是推扫式线阵成像,焦距动辄几米,轨道高度几百公里,单景覆盖几十公里,同一区域能拿到的多视影像往往是不同轨道、不同侧摆角拼起来的,基高比小得可怜。
基高比小意味着什么?深度方向的不确定性被成倍放大。你在影像上哪怕只差半个像素的匹配误差,反投影到地面可能就是几米甚至十几米的高程偏差。再叠加推扫成像时姿态的连续变化、多片 CCD 之间的拼接误差、RPC 参数本身是拟合出来的近似模型,误差链条比近景长得多。
另一个差异是场景内容。卫星影像一次覆盖几十平方公里,里面什么都有:水面、阴影、沥青路面、大片同类屋顶、成排的树木。这些区域纹理极弱或者重复,逐像素独立匹配几乎必然出错。城里还有高楼遮挡,一个视角看得见的立面,另一个视角是背坡,多视一致性直接失效。近景数据里你可以靠补拍解决,卫星数据你补不了,只能靠算法本身扛住。
还有尺度问题。几十平方公里的数据量,单机内存根本放不下整块的稠密匹配,必须分块。分块之后块与块的接缝、边界处的深度不连续、跨块的点云融合,全是新问题。通用三维重建工具大多没为这种尺度设计,跑到一半内存爆掉是常态。
所以我后来选方案的判断标准很简单:它必须原生理解 RPC 模型,必须支持大范围分块处理,必须有针对弱纹理的多假设机制,最后还得有办法量化评估成果精度。这几条一摆,可选范围就窄了。
1.2 “先建后验”这套架构到底解决了什么
Danesfield 最核心的设计思路是先建后验,也就是先生成假设、再逐条验证。听起来像句废话,但和传统的赢家通吃策略比,差别非常大。
传统稠密匹配的思路是:对参考影像上的每个像素,在搜索范围内找到匹配代价最小的那个深度,直接取它。这个策略在纹理丰富、视差清晰的时候又快又准,但在卫星影像这种弱纹理、小基高比的场景里,代价曲面的最小值往往非常平坦,稍微一点噪声就能让最小值漂到完全错误的位置,而且算法自己毫无察觉,错得理直气壮。
先建后验换了个路子。它先在局部生成一批候选深度假设,每个假设对应一个三维点;然后把这些三维点投影到其它视角的影像上,看它们在那些视角里是不是真的落在一致的、纹理相似的位置上。只有通过多视角一致性检验的假设才会被保留下来,剩下一批候选,再从中挑最优的。关键在于,验证环节是“外部裁判”,它不依赖参考影像自身的匹配代价,所以对弱纹理的容忍度高得多。哪怕参考影像上那块区域一片平滑,只要在别的视角里能被验证,深度就能被确定。
这套架构在实现上分了几层。最底层是逐像素或逐块的深度假设生成与验证,产出一张张带置信度的深度图;中间层把多张深度图融合成统一的三维点云,处理冲突和冗余;最上层从点云生成网格并做纹理映射。每一层都有自己的失败模式,也都有自己的调参空间,后面几节会挨个拆。
我个人的体会是,理解这套架构比记住命令重要得多。因为一旦结果不对,你得知道问题出在假设没生成对,还是验证没通过,还是融合的时候被错误地剔除掉了。这三类的排查方向完全不同。
1.3 主流开源方案横向对比
为了让选型过程有据可循,我把实际试过的几套方案按卫星影像关心的维度列了个表。需要说明的是,这些评价基于我手头那批亚米级城市影像,换数据可能结论有出入。
| 方案 | RPC 模型支持 | 大场景分块 | 束调整能力 | 网格与纹理 | 精度评估工具 | 上手成本 |
|---|---|---|---|---|---|---|
| Danesfield | 原生,作为一等公民 | 内建,按瓦片切分 | 支持带控制点的 RPC 补偿优化 | 有完整链路 | 自带基于检查点的评估模块 | 中高,编译依赖多 |
| COLMAP | 弱,主要面向针孔相机 | 有限,靠手工切块 | 强,但相机模型不匹配 | 有 | 无 | 中,文档好 |
| OpenMVG + OpenMVS | 弱,需自己转相机模型 | 有限 | 支持 | 有 | 无 | 中 |
| MicMac | 有 RPC 支持 | 支持 | 支持 | 有 | 部分 | 高,文档偏法语习惯 |
| 通用立体匹配工具箱 | 视工具而定 | 多数不支持 | 通常无 | 通常只到点云 | 视情况 | 低到中 |
从表里能看出来,COLMAP 和 OpenMVG 这类工具在相机模型和优化框架上做得非常扎实,但它们的设计出发点就是地面或近景的针孔相机,你把 RPC 硬塞进去,等于让一个精通室内摄影的人去干航空测绘,能用但处处别扭。MicMac 在遥感圈子里口碑不错,功能覆盖也全,只是文档的组织方式和参数命名习惯需要适应一段时间。
Danesfield 的优势在于它是从卫星影像这个约束出发倒推设计的:RPC 是核心输入而不是补丁,分块是内建机制而不是外挂脚本,评估模块直接对接测绘上常用的检查点精度指标。代价是依赖链比较长,编译一次要花点耐心,这也是下一节要重点讲的。
有一点必须提醒:这套软件不是一个双击就能用的图形界面工具,它是一组命令行程序的集合,每个子命令负责一个环节,你需要自己把它们串成流水线。如果你期待的是一键出结果,那它可能会让你失望;但如果你需要的是能看清每一步在干什么、能单独调某一个环节的工程化工具,这种设计反而是优点。
2. 环境搭建与依赖编译:从零到跑通
2.1 依赖清单和版本约束
这套东西的依赖不算少,而且版本敏感。我踩过的最大教训就是不要试图在一个已经装了大量科学计算包的现成环境里编译,版本冲突能让你怀疑人生。后来我的做法是固定一个干净的容器镜像或者独立虚拟环境,一次配好,之后复用。
核心依赖大致是这些:C++ 编译器(GCC 7 以上,建议 9 或更新)、CMake 3.16 以上、GDAL(必须带地理坐标和 RPC 相关支持,这个是最容易出问题的)、Boost、Eigen3、Ceres Solver(用于非线性优化,就是束调整那一步的心脏)、OpenCV、VTK(用于网格和可视化相关的数据结构)、PDAL(点云读写)、PROJ(坐标转换)。部分模块如果要开 GPU 加速,还要 CUDA 工具链,但这一步是可选的,先把 CPU 路径跑通再说。
几个具体的版本坑,实测下来值得记一笔。GDAL 的新旧版本在栅格读写和 RPC 元数据接口上有过不兼容的改动,编译时报一堆找不到符号的错误,八成是版本对不上,去看 CMake 的查找日志能定位到具体版本。VTK 在大版本跃迁时改了不少类名和头文件路径,遇到编译到一半挂掉且报错集中在渲染相关文件,优先怀疑它。Ceres 依赖 Eigen 和 SuiteSparse,如果系统里 Eigen 版本太老,Ceres 编译能过但运行束调整时会给出数值异常的结果,这种“能跑但算错”的情况最阴险。
Ubuntu 系上一份基础安装大概长这样,具体包名以你的发行版为准:
sudo apt update sudo apt install -y build-essential cmake git \ libgdal-dev libboost-all-dev libeigen3-dev \ libceres-dev libopencv-dev libvtk7-dev \ libpdal-dev proj-bin libproj-dev注意:不同发行版里 VTK 的包名差异很大(libvtk7-dev、libvtk9-dev 等),装之前先用 apt search 确认一下,别照抄。
如果发行版自带的版本太老,比如 Ceres 或者 GDAL,那就得源码编译。我自己的选择是 GDAL 和 Ceres 走源码,其余用包管理器,这样能兼顾可控性和搭建速度。源码编译 GDAL 时记得把需要的驱动都开上,别为了省时间全关掉,后面读影像格式不支持又得重来。
2.2 构建过程与典型报错
构建本身不复杂,标准的 CMake 流程:
git clone <仓库地址> danesfield cd danesfield mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/danesfield \ -DBUILD_TESTING=OFF make -j$(nproc)-DCMAKE_BUILD_TYPE=Release这个参数别省。我一开始图省事用了默认配置,结果稠密匹配那一步慢了将近一个数量级,白白浪费了一下午。并行编译的线程数按物理核心给,给太高反而因为内存吃满被系统杀掉。
编译期的报错大致分三类,我自己遇到过的整理如下:
第一类是依赖找不到。CMake 输出里出现Could NOT find GDAL之类,先确认pkg-config --modversion gdal能不能输出版本号,如果不能,说明开发包没装或者路径没进环境变量。这种情况优先装 -dev 包,别去手工改 CMakeLists。
第二类是头文件和库版本错配。表现是编译到某个模块时报undefined reference或者结构体成员不存在。这时去看 CMake 的查找日志,确认它找到的是不是你期望的那一份库。系统里同时存在多个版本的 GDAL 是常见的坑,ldconfig -p | grep gdal能看清全局情况。
第三类是编译期内存溢出。大模板类的模块在make -j高并发时能吃掉大量内存,被内核 OOM 杀掉时终端只留下一句莫名的报错。把并发数降到核心数的一半通常就过了。
编译完成后,bin 目录下会有一堆可执行文件,每个对应一个处理环节。不同版本之间子命令的命名和参数做过调整,所以我的建议是每次升级后先跑一遍--help,别迷信旧脚本。
2.3 数据准备:比编译更容易翻车的地方
我用下来最深的感受是,这套工具链的失败案例里,数据问题占的比例远高于程序问题。影像和元数据没整理干净,后面会以各种诡异的形式报错,而且报错信息往往指不到真正的原因。
一份能跑通的输入至少包含:影像文件本身、每景对应的 RPC 参数、影像之间的相对路径清单、可选的相机内参补充信息和地面控制点。RPC 通常内嵌在影像的元数据里,也有的以独立文本文件形式提供,两种情况这套工具都认,但你需要确认它确实找到了。有些影像在格式转换或重采样之后 RPC 会丢失,这是非常常见的问题,处理流程里千万不能随手用别的工具转一遍格式。
我做了一份上线前的检查清单,每次拿到新数据先过一遍:
| 检查项 | 为什么要查 | 不查的后果 |
|---|---|---|
| RPC 是否存在且行数正确 | 它是几何定位的唯一依据 | 直接报错或定位结果整体偏移 |
| 位深与波段数是否一致 | 批处理假设统一格式 | 读入时截断或越界 |
| NoData 值是否统一 | 边界黑边会被当成有效纹理 | 边缘出现大量错误点 |
| 影像清单路径是绝对还是相对 | 相对路径依赖工作目录 | 批量跑时找不到文件 |
| 所有影像坐标系是否一致 | 混合坐标系会导致高程基准错乱 | 成果整体高程偏差 |
| 高程基准是椭球高还是正高 | 两者差几十米很常见 | 成果和实测对不上 |
最后一条特别容易忽略。RPC 模型输出的通常是相对于某个椭球的高程,而你拿到的检查点是水准高程,中间差着一个高程异常值,不做转换直接比对,会得出“精度差几十米”的错误结论,然后一头扎进算法里找问题,找一辈子也找不到。
影像清单我一般手工整理,一行一景,字段包括路径和可选的权重、掩膜信息。这个文件是整个流水线的入口,建议单独版本管理,别用脚本临时生成,出问题的时候你至少能回溯到改了哪一行。
3. 核心流程实操:从原始影像到带纹理网格
3.1 第一步:束调整,别跳过这一步
很多教程会告诉你“RPC 已经给了地理定位,直接做稠密匹配就行”,这个说法在有控制点需求的项目里是危险的。RPC 参数是通过对严格成像模型拟合得到的一组有理多项式系数,它本身就是近似,拟合残差、姿态测量误差、时间同步误差叠在一起,单景内部可能有系统性形变。多景之间如果不做统一平差,直接三角化出来的点云会出现明显的分层和错位,表现为同一栋楼在不同影像里的重建高度对不上。
束调整这一步要干的事,就是利用影像间自动提取的连接点,配合少量地面控制点,对每景的 RPC 施加一个补偿变换(常见的是仿射或平移补偿),把多景统一到一个一致的几何框架里。补偿参数数量远少于完整的相机内外参,所以只需要很少的控制点就能约束住,这也是它在卫星影像上比完整自检校更实用的原因。
实际操作上,流程是先把影像清单喂进去做特征提取与匹配,得到连接点;然后带上控制点文件做优化。我一般会先不带控制点跑一遍,看看连接点的残差分布,如果残差本身就很大很散,说明匹配质量有问题,这时候加控制点也没用,得回头查数据。
一个实用技巧:控制点别全用来参与平差,留出三分之一作为检查点,平差时不用,后面评估时再用。这样评估出来的精度才是真实的,全参控制点算出来的残差必然好看。
平差完成后会输出更新后的几何参数文件,后续所有环节都必须用这一份,别不小心又指回原始数据。
3.2 第二步:稠密化,参数怎么定
稠密化是整个流程里最耗资源的一步,也是最需要按数据特性调的一步。它的大致过程是:把作业区切成瓦片,在每块瓦片里选定参考影像,生成深度假设,做多视一致性验证,最后把所有瓦片的深度图融合成点云。
第一个要定的参数是输出分辨率。理论上你能做到的最佳分辨率取决于影像的地面采样间隔,而地面采样间隔可以由像元尺寸、焦距和成像高度估算:地面采样间隔约等于像元尺寸乘以成像高度再除以焦距。举个虚构的例子,某亚米级影像像元尺寸 8 微米,焦距 5 米,成像高度 500 公里,算下来地面采样间隔大致在半米量级。但实际重建分辨率没必要追到这个极限,一方面小基高比下更高的分辨率只会放大噪声,另一方面计算量是按面积平方涨的。
我的经验做法是先按 1.5 到 2 倍地面采样间隔跑一遍,看看整体形态对不对,再往下压。城区高楼区域可以适当粗一点,因为立面重建本身的可靠性就有限;平坦开阔地可以细一点。
第二个参数是瓦片大小。这个直接和内存挂钩。瓦片太小,块间接缝多,融合阶段容易在边界产生台阶;瓦片太大,内存扛不住。我的经验是让单块瓦片的原始影像数据量控制在可用内存的三分之一左右,留出余量给中间结果。
第三个是每个像素的最少有效视角数。这个参数决定了验证的严格程度。设得太低,弱纹理区域的错误假设会被放过;设得太高,遮挡严重的高楼背坡会大片空洞。城区数据我一般从三开始试,山区或遮挡少的地方可以提到四。
跑完稠密化,先别急着做网格。把点云按高程渲染看一眼,如果看到整片区域有明显的条纹状起伏、大面积规则空洞、或者建筑边缘像被刀切一样平整,说明参数或者输入有问题,这时候继续往下走纯属浪费算力。
3.3 第三步:网格生成与纹理映射
点云到网格这一步,本质是在噪声和细节之间找平衡。原始点云带着匹配误差,直接三角化出来的表面会像砂纸一样粗糙。常见做法是先做一定程度的平滑或降噪,再重建表面。
这一步的参数里,我关注最多的是保留细节的尺度和孔洞填补的策略。保留尺度设得太小,噪声全保留,网格面数爆炸还难看;设得太大,屋顶边缘被磨圆,建筑的几何精度就没了。城区数据我的经验是把平滑尺度控制在两到三个地面采样间隔之间,既能压住匹配噪声,又能保住主要的建筑轮廓。
孔洞填补需要谨慎。水面、阴影、遮挡区天然就是没有有效点的,算法填出来的东西是猜的,不是测的。这类填补区域在成果交付时最好单独标记出来,别和实测区域混在一起用,尤其是下游要做方量计算或者坡度分析的场景。
纹理映射这一步相对直观,就是把影像反投影到网格表面,生成纹理图集。需要注意的是接缝处理和视角选择。同一块墙面在不同影像里都有观测时,程序会自动挑质量最好的那张,但如果你发现成果里某些墙面明显发暗或者模糊,多半是挑到了侧摆角很大、分辨率被拉伸的那一景。可以在配置里手动调整视角选择的惩罚项,让程序优先选接近正射的观测。
3.4 第四步:精度评估,别凭肉眼看
成果看着漂亮和成果能用是两件事。评估环节拿前面留出的检查点,计算高程方向的均方根误差和中误差,还有平面方向的偏移量。测绘上常用的指标是检查点高程均方根误差和 LE90,前者反映整体离散程度,后者反映 90% 的点落在多大的误差带内。
评估输出通常还能生成误差分布和剖面图。剖面图是我最看重的,沿着一条穿过城区的线切一刀,看重建的地面和实测点的高程剖面能不能贴合。整体指标好看但剖面在某一段突然抬升,往往意味着那一带有一景影像的补偿参数出了问题,或者有局部遮挡没处理好,这类问题看总量指标是看不出来的。
我的习惯是每次调完参数都存一份评估结果,做成一个简单的表格比对。参数和精度的关系不是单调的,经常出现“这组参数在 A 区域好、在 B 区域差”的情况,不做记录根本理不清。
4. 参数调优与性能优化实战
4.1 分辨率、数据量与耗时的三角关系
调参之前先建立一个基本认知:整个流程的计算量大致和你设定的重建分辨率平方成正比,和参与重建的影像数量成正比,和作业区面积成正比。这三个因子互相牵制,你不可能同时把三者都拉满。
我做过一组实测,同一批城区数据,作业区大约十几平方公里,参与影像若干景。按两倍地面采样间隔跑,单机多核大概几小时量级;把分辨率压到接近一倍地面采样间隔,时间涨了将近四倍,而高程精度的提升非常有限,因为瓶颈已经从分辨率变成了几何条件。这个结论很重要:在基高比受限的卫星数据上,一味提高重建分辨率是在做无用功。
所以我的调参顺序永远是先粗后细。先用低分辨率跑全区域,确认几何对齐没问题、点云形态合理;然后挑一两个有代表性的小区域,用高分辨率跑,评估精度上限;最后再决定整个作业区用哪个折中参数。
影像数量也是个变量。增加视角数量能提升弱纹理区域的可靠性,但计算量线性上涨,而且视角多到一定程度后收益就饱和了。我的经验是同一区域五到八景是比较舒服的区间,再多就要考虑是不是只挑侧摆角分布均匀的那些。
4.2 内存、线程与分块策略
内存是这条流水线上最硬的约束。稠密化阶段的内存占用大头是影像金字塔的缓存、深度图缓冲和点云写入缓冲。我的排布经验是:把单块瓦片的影像缓存控制在物理内存的三到四成,深度图缓冲留两成,剩下的给系统和其他中间数据结构。
线程数不是越多越好。我做过的对比里,线程数从核心数的一半提到全部,速度只快了不到两成,而峰值内存涨了三成,在某些机器上直接触发交换分区,整体反而变慢。所以保守一点给线程数更划算。
磁盘 IO 经常被忽略。这类流程中间会写大量临时文件,深度图、分块点云、日志。如果用机械盘或者网络存储,IO 瓶颈能让 CPU 全程闲着等数据。我的建议是临时目录放在本地固态盘,输出目录最后再同步走,速度差距非常明显。
还有一个实战技巧:如果作业区里存在大量水体或者常年阴影,先在预处理阶段做个掩膜。让匹配算法在无效区域上白白消耗算力,还会生成一堆需要后期清理的垃圾点,得不偿失。
4.3 精度调参的推荐路径
我把自己的调参顺序总结成一条路径,供参考:
第一步,固定几何。先确认束调整输出的连接点残差在合理范围内,控制点参与平差的残差分布均匀、没有明显的系统性方向偏移。这一步不过关,后面所有调整都是假的。
第二步,调验证严格度。在几个有代表性的小区域上,只改最少视角数这一个参数,观察点云密度和错误点的变化。找到一个错误点明显减少但有效点还没大幅下降的拐点。
第三步,调分辨率。按前面说的,从粗到细试两档,看评估指标的边际收益。
第四步,调网格平滑。这一步主观性强,建议用同一块区域的三维视图反复比对,主要看建筑边缘的锐利程度和屋面的平整度能不能兼顾。
每一步只改一个变量,改完立刻存档并记下评估结果。这条纪律看着啰嗦,但在十几个参数面前,不这么做你三天后就会彻底忘记哪组参数是什么效果。
5. 常见问题排查速查表与避坑经验
5.1 报错定位思路
我把这两年遇到的典型问题整理成了一张表,按现象查比按报错文字查更管用,因为同一类问题的报错信息经常千奇百怪。
| 现象 | 高概率原因 | 排查动作 |
|---|---|---|
| 启动即报找不到影像 | 清单路径是相对路径且工作目录不对 | 改成绝对路径重试 |
| 读影像时报波段或位深不符 | 输入影像格式不统一 | 逐景检查位深、波段、NoData |
| 定位结果整体偏移几百米甚至更多 | RPC 缺失或未正确读取 | 检查元数据,确认读到了 RPC |
| 高程整体差一个常数 | 高程基准不一致 | 确认是椭球高还是正常高 |
| 点云出现规则网格状空洞 | 瓦片边界融合问题 | 调整瓦片大小或重叠度 |
| 高楼区域大面积空洞 | 遮挡导致验证失败 | 降低最少视角数,或接受立面缺失 |
| 水面区域大量错点 | 弱纹理误匹配 | 加水体掩膜排除 |
| 束调整不收敛 | 连接点中粗差过多 | 打开粗差剔除,降低残差阈值 |
| 运行中途被杀 | 内存超限 | 减小瓦片、降低线程数 |
| 成果网格出现明显接缝 | 跨块平滑不一致 | 增加瓦片重叠,统一平滑参数 |
表格里最值得展开的是“高楼区域大面积空洞”这一条。这不是 bug,是物理限制。建筑物的背坡面在参与重建的所有影像里可能都不可见,理论上就不可能重建出来。我早期花了很久想通过调参数把它补上,最后发现唯一办法是增加不同侧摆角的影像,或者接受立面缺失。这个认知转变省了我很多时间。
5.2 数据层面的隐性坑
有几个坑不在报错里,但会以“结果莫名其妙不对”的形式出现,我单独拎出来说。
第一个是影像的辐射差异。不同时间、不同季节拍的影像,地表反射率差别可能很大,同一片草地在两景里一景偏黄一景偏绿。匹配算法用纹理相似度做验证,辐射差异大时相关性会下降,导致本来应该匹配上的点被判定为不一致。处理办法是在预处理阶段做一次简单的直方图匹配或者相对辐射归一化,成本很低,收益明显。
第二个是云和云的阴影。卫星影像有云太正常了,云区完全无法重建,云的阴影还会让地面纹理消失,同时造成虚假的深度跳变。上流程之前先做一遍云检测掩膜,能省掉后面大量的清理工作。
第三个是影像的几何精度本身不一致。有的景可能做过正射纠正,有的没有;有的做过几何精校正,有的只有原始 RPC。混合在一起做平差,出来的连接点残差会呈现按景分组的系统性偏移。这种情况我遇到过一次,排查了大半天,最后发现是一景数据的处理级别和别人不一样。所以数据入库时一定要记录每景的处理级别和来源。
5.3 结果异常的判读经验
最后分享几个我用来快速判断成果有没有问题的“肉眼检查法”,比看指标快。
把点云按高程着色,从正上方俯视。健康的成果里,道路、广场这些平坦区域的颜色应该高度均匀,如果看到明显的波浪状起伏,说明几何对齐有问题或者匹配噪声太大。建筑物边缘应该是清晰的直线段,如果边缘发毛、呈锯齿状扩散,说明分辨率不够或者平滑过度。
再切一个剖面看地平线。沿一条穿过城区的直线取高程剖面,地面应该是一条相对平缓的曲线,建筑处出现矩形凸起。如果剖面里出现周期性的锯齿,八成是瓦片边界的问题;如果某个区段整体抬高或压低,去查那一带的影像是不是有系统性问题。
还有纹理成果的检查。把带纹理的网格转成正射视图,和原始影像叠在一起做闪烁对比。接缝处的纹理错位、墙面纹理的拉伸、屋顶纹理的重影,都能在这步暴露出来。这一步花十分钟,比后面交付后被返工省事得多。
我个人在实际操作中的体会是,这套工具真正的门槛不在编译,也不在参数,而在于你得先想清楚自己手里的数据能支撑什么样的精度,然后按这个预期去设计流程。卫星影像的三维重建从来不是“跑个程序就出结果”的事,它更像一次需要反复校准的实验:先建立基线,再逐个变量调整,每一步都留下记录。我见过太多人一上来就把分辨率拉满、参数全开,跑了两天内存爆掉,最后连一次完整结果都没见到。稳妥的做法是先挑一块两平方公里左右、有检查点、地形不复杂的区域,把整条链路跑通、把精度摸清楚,再往外扩。这个顺序看着慢,其实是唯一快的方式。