简介面向无人机航拍场景的三维重建算法学习与开发者资源提供从图像采集、特征提取与匹配、相机定位到模型优化的一整套Python实现既适合计算机视觉研究者入门也适合有摄影测量基础的工程师进行工程复现。压缩包共54个文件以41个Python脚本为核心覆盖数据预处理、模型训练、轨迹对齐与误差评估等环节另含3个YAML配置、2个notebook演示、2个视频和2张效果图等辅助材料整体体积20.66MB结构清晰便于按模块研读。项目源码完整开放可直接观察dpt深度估计、NeRF网络、位姿对齐等关键算法的具体实现并配有实验录屏与正射投影效果展示。自发布以来已有681人学习下载是兼顾学术研究与项目实战价值的优质参考资料。1. 无人机航拍三维重建这份算法实现源码包到底能帮你走到哪一步先把结论放在前面这份基于无人机航拍场景的三维重建算法实现不是一个“一键出模型”的傻瓜包而是一条能从原始航片走到三维模型、正射投影和体积测量的完整算法链路。我拆完源码后发现项目里真正花力气的地方不是 NeRF 训练本身而是相机位姿估计与轨迹评估——这两块没做好后面重建得再漂亮也是飘的。源码按预处理、模型、评估、脚本四层组织适合想读 COLMAP NeRF DPT 这套组合拳的研究者也适合需要用无人机拍建筑物、工地或地形的工程人员。新手跟步骤能跑通熟手可以直接把 ATE 评估和数据预处理脚本抄进自己的管线。需要完整项目源码的话往下看到每一章对应的文件和用法再决定要不要下载。2. 航拍数据准备先搞懂 SfM 位姿解算再谈三维重建2.1 为什么第一关永远是相机位姿二维图像本质上是三维点经过相机投影后的结果。给定同一场景的多张图片如果不知道每张图拍摄瞬间相机在世界坐标系中的位置和朝向三维点是没法被三角化出来的。无人机航拍的优势是空中视角多、覆盖范围大但缺点也很明显整体尺度大、纹理重复、帧与帧之间位移较大这会让特征匹配和位姿估算比普通手持拍摄更容易出问题。运动恢复结构Structure from Motion就是专门解决这个问题的。常见流程是先用 SIFT 或 SuperPoint 提取图像特征点再用最近邻搜索匹配特征描述子之后通过本质矩阵分解出相机位姿最后用三角化得到稀疏三维点云并做光束法平差来同时优化相机内参、位姿和三维点。项目里虽然主力重建网络是 NeRF但 NeRF 训练的前提就是已经拿到了相对准确的相机位姿。所以我把这份源码拆开后的第一个判断是真正决定重建质量上限的是 SfM 这一步。后续的 DPT 深度估计和 NeRF 体渲染都是在“位姿已经基本正确”的假设下做精细化。如果一上来就用原始视频帧直接喂网络大概率得到的是扭曲的几何。项目里专门放了一个scripts/get_matrix_by_sfm.py就是把你用 COLMAP 跑出来的稀疏重建结果整理成后续训练要用的位姿矩阵。这一步的产出如果不对后面所有模块都会被带偏。2.2 跑通 COLMAP 并导出位姿矩阵项目源码里的get_matrix_by_sfm.py承担的是“把 COLMAP 输出翻译成 NeRF 输入”的桥接工作。COLMAP 的命令行工具有三个主要阶段我一般会这样组织脚本# 1. 提取特征 colmap feature_extractor \ --database_path data/colmap.db \ --image_path data/input_images \ --ImageReader.single_camera 1 \ --ImageReader.camera_model SIMPLE_RADIAL # 2. 特征匹配航拍建议用 exhaustive_matcher别用 sequential colmap exhaustive_matcher \ --database_path data/colmap.db # 3. 稀疏重建 colmap mapper \ --database_path data/colmap.db \ --image_path data/input_images \ --output_path data/colmap_models这里的single_camera表示整批航片用同一台相机对固定摄像头、固定焦距的无人机来说应该设为 1可以显著减少需要优化的相机数量。camera_model选SIMPLE_RADIAL是很多无人机影像的默认选择只带一个径向畸变参数在畸变不严重的影像上足够。匹配策略上航拍相邻帧重叠率有保证但只做相邻帧匹配会锁死在航线顺序上一旦飞机掉头或偏移闭环检测不出来用exhaustive_matcher会让匹配时间变长但轨迹漂移会小很多。这个时间成本我认为值得花。跑完 mapper 后data/colmap_models/下会有0/目录里面有cameras.bin、images.bin、points3D.bin。get_matrix_by_sfm.py的常见用法是把这些二进制文件读出来转成每个训练视角的相机外参矩阵4×4 的 world-to-camera 矩阵和相机内参焦距、主点。这些矩阵会按帧名顺序存成一个清单文件供 dataloading 模块读取。如果你之前用的是 COLMAP 的 GUI 界面导出的是文本格式命令行跑出来的是二进制格式读写逻辑不太一样最好统一走脚本。2.3 读懂项目里的位姿文件与数据集配置打开configs/目录能看到default.yaml、preprocess2.yaml还有Tanks相关配置。这是项目为了兼容多数据集做的统一配置入口。我建议先改default.yaml里面主要设置数据根目录、图像分辨率、训练帧数和模型类型。# configs/default.yaml 中我会优先改的几项 data_root: data/colmap_models image_path: data/input_images camera_mask: # 留空表示使用全部图像 scale_factor: 2 # 图像缩放倍数数值越大分辨率越低 train_epochs: 200 batch_size: 1scale_factor这个参数容易被忽略。无人机拍出来的图通常是 4000×3000 左右直接全分辨率送进 NeRF 显存立刻爆炸设为 2 或 4 是在细节和显存之间做取舍。我一般会先设为 2 跑一个小规模测试确认位姿和几何没大问题后再用更精细的分辨率做最终重建。Tanks配置对应的是 Tanks-and-Temples 那类街区/室外的基准数据集结构是“每台相机一个文件”里面每行存相机位姿。如果你有自己的无人机航拍数据不需要强行套 Tanks 的结构只要把位姿矩阵整理成项目dataloading/dataset.py能读的格式就行。读源码时重点关注dataset.py里对位姿矩阵的读取顺序——是先做了 world-to-camera 变换还是 camera-to-world。方向搞反后面 NeRF 训练出来的新视角会整体镜像。我自己第一次跑这个项目时就在这里吃过亏以为位姿文件格式没问题结果渲染出来的模型左右颠倒排查了半天才发现是读取顺序和 COLMAP 输出的坐标系约定不一致。2.4 从航拍视频抽帧先别把每一帧都喂进去项目资源里附带wurenji_small_resolution.mp4、gaoqing.mp4等航拍视频如果要从视频重建第一步是抽帧。常见做法是用 ffmpeg 按间隔抽帧。航拍视频帧率通常 30fps航线过程中相邻两帧重叠率过高不仅浪费算力还会导致 SfM 匹配出现冗余。一般按 2 秒或 3 秒抽一帧或者先每帧提取特征再用特征数量过滤掉模糊帧。# 从航拍视频中每 2 秒抽一帧并缩放到合适的尺寸 ffmpeg -i wurenji_small_resolution.mp4 \ -vf fps1/2,scale1920:-2 \ -q:v 2 \ data/input_images/frame_%04d.jpgfps1/2的意思是每两秒输出一帧而不是每两帧输出一帧这个参数很多人会搞混。scale1920:-2把长边限制到 1920同时保持宽高比-2是为了让宽高都变成偶数避免后续编码报错。抽帧间隔不是固定的如果视频里有明显的转弯、爬升、悬停段我会在这些段落加密抽帧直线巡航段稀疏抽帧。抽帧完成后先随机挑 20 张图放进 COLMAP 跑一次几分钟就能看出数据有没有大问题不需要等全量跑完。从这章能看出来整个项目的所有模块都建立在“位姿文件格式统一”这个前提上。宁可多花半天把位姿整理清楚也不要急着训练。我自己的习惯是每跑一段 SfM先把导出的位姿画出来看一眼确认相机运动轨迹没有飞来飞去的跳变再进入下一步。3. NeRF 隐式重建与轨迹评估从体渲染到 ATE 精度分析3.1 为什么这条管线选 NeRF而不是传统 MVS传统多视图立体MVS流程是先把相机位姿算出来然后对每一帧生成深度图再融合成稠密点云和网格。这个流程在纹理丰富、光照稳定的室内场景很成熟但放到无人机航拍里会遇到两个问题一是高空视角下地面纹理经常重复草地、屋顶、路面特征匹配很容易产生错误深度二是 MVS 深度图对光照变化非常敏感早晚航班的光照角度不同会导致同一栋楼两边重建厚度不一致。NeRF 的思路完全不同。它不显式地估计每个像素的深度而是用一个小型 MLP 把整个场景编码成连续的体积密度和颜色场。给定一条相机光线沿光线采样若干个空间点查询密度和颜色再用体渲染积分公式合成该像素的颜色。这样训练出的模型天然平滑对弱纹理区域更友好。项目里model/official_nerf.py就是按 NeRF 原始论文结构实现的粗网络负责整体密度分布细网络在密度高的地方做更多采样两者一起优化。工程上选 NeRF 的代价是训练时间长、需要较精确的位姿并且对相机内参错误很敏感。但在这个项目里前面已经用 COLMAP 拿到了位姿NeRF 承担的是“隐式几何重建”的角色所以算是合理选型。这几年 3D 高斯重建3DGS很火速度比 NeRF 快不少但如果你想读懂体渲染和位姿误差传播这份源码的 NeRF 实现更适合一行行啃。对无人机航拍的大尺度场景3DGS 的显存占用和训练控制其实更麻烦NeRF 反而更直观。3.2 模型训练管线network.py、losses.py、training.py 怎么配合看文件结构model/下除了official_nerf.py还有network.py、losses.py、training.py、distortions.py、intrinsics.py。我理解的分工是network.py定义了 MLP 主干和颜色/密度输出头distortions.py处理图像畸变补偿intrinsics.py维护相机内参矩阵losses.py计算渲染颜色与真实颜色之间的误差training.py把采样、查询、渲染、反传串成完整训练循环。核心训练循环大致是这样的# model/training.py 中单步训练逻辑的简化示意 for batch_rays, batch_rgb in dataloader: # 1. 采样光线和近远边界 rays_o, rays_d batch_rays # 2. 粗网络采样均匀采样 64 个点 rgb_coarse, density_coarse nerf_network(rays_o, rays_d, coarseTrue) # 3. 细网络采样根据粗网络密度做重要性采样 rgb_fine, density_fine nerf_network(rays_o, rays_d, coarseFalse) # 4. 计算 L2 颜色误差 loss losses.compute_loss(rgb_coarse, rgb_fine, batch_rgb) optimizer.zero_grad() loss.backward() optimizer.step()这里的粗网络和细网络共享同一个场景 MLP但采样策略不同。粗网络在近远边界上均匀采 64 个点得到一个大致的密度分布细网络再根据这个分布额外采 128 个点把点集中到密度高的表面附近最终渲染颜色主要靠细网络的输出。losses.py里除了 L2通常还会加一点正则项来抑制密度离群点不过项目里默认配置下 L2 占绝对主导。训练时batch_size1意味着每次只处理一条光线这对显存友好但网络收敛速度慢实际训练建议开多进程并行采样。无人机航拍图分辨率高如果直接对全图所有像素逐条光线训练迭代一轮要几十万光线。项目里train.py会先按configs/default.yaml里的scale_factor降采样再以随机抽取光线的方式训练。我一般会把train_epochs先设到 50 轮跑通流程确认 loss 持续下降再把轮数加到 200 以上。如果 loss 前期下降但中后期震荡优先检查位姿文件里有没有个别帧的矩阵写错而不是调学习率。另外还要注意eval_poses.py和eval_pose_one_epoch.py这两个文件它们实现了在训练过程中用 NeRF 反推相机位姿也就是把位姿也当成可优化变量。如果 SfM 的结果里某几帧误差明显可以在训练阶段把这些帧的位姿设为可学习参数做一轮位姿精化比手工删帧更省事。3.3 ATE 轨迹评估comp_ate.py 和 align_utils.py 到底在算什么无人机航拍重建应用中光看渲染图“好看”是不够的。很多时候你需要知道估计的相机轨迹和真实轨迹差多少这就是 ATEAbsolute Trajectory Error指标的用途。ATE 计算的是估计位姿和真实位姿之间经过最优变换对齐后的均方根误差单位通常为米。项目里utils_poses/comp_ate.py、align_traj.py、align_utils.py就是干这个的。实际用法常见是这样python utils_poses/comp_ate.py \ --est model_output/pred_traj.txt \ --gt data/gt_traj.txt \ --align sim3 \ --output results/ate_result.json--align sim3表示用相似变换对齐7 自由度旋转 3 平移 3 尺度 1这是最重要的参数。因为 COLMAP 输出的轨迹坐标通常和真实轨迹坐标系不在一个原点尺度也可能不是米必须先做对齐再算误差。align_utils.py里用的 Umeyama 算法就是解决这个问题的最常见实现。transformations.py则提供了四元数、旋转矩阵、齐次矩阵之间的互相转换trajectory_utils.py负责把 TUM 格式每行时间戳 位置 四元数读进来。跑完会有一个结果文件我可以整理成一个简单的验收表指标含义参考关注点ATE RMSE绝对轨迹误差均方根整体位姿精度大于 1m 时要注意ATE mean平均误差偏差的系统性对齐前/后误差是否用了 Sim(3) 对齐对齐后误差仍在 5m 以上说明位姿估计失败我自己的习惯是每完成一轮 SfM 位姿解算先跑一次 ATE把结果记下来。后面如果不小心改了抽帧间隔再比较一次就能看出是数据问题还是算法问题。这个“先对齐再评估”的步骤很多人第一次跑会忽略然后被几米甚至几十米的误差吓到实际上只是坐标系没对齐。对齐之后如果 ATE 仍然偏大我会把align_traj.py生成的轨迹可视化文件导出来用vis_cam_traj.py画出每帧相机位置一眼就能看到是哪一段航线发生了漂移。4. 深度估计与稠密重建DPT 模型把隐式场拆成可用的几何4.1 DPT 在管线里的位置为什么还需要单目深度估计NeRF 训练完能渲染任意视角但如果要做正射投影、算土方体积、导入 GIS 系统还是需要稠密的三维点或网格。NeRF 本身可以输出深度图体渲染中对密度积分但它的深度是基于训练视角重建的视角外推算不太可靠。因此项目在preprocess/下放了dpt_depth.py和dpt_depth.ipynb用 DPTDense Prediction Transformer对航拍原图生成单目深度图。DPT 是现阶段很常见的单目深度估计模型输入一张 RGB 图输出对应的深度图。它的好处是模型对场景结构有一定泛化能力能补出纹理稀疏区域的深度。在无人机航拍场景里我一般把它当作“辅助稠密化”手段先用 COLMAP 得到稀疏点云和相机位姿再用 DPT 生成每帧深度最后把深度图反投影成稠密点云。这样比直接跑传统 MVS 要可靠也比纯 NeRF 输出更快。要注意的是DPT 是单目估计它给出的深度尺度是相对的必须和已知的相机位姿或稀疏点云对齐后才有物理意义这是整个第 4 章最容易出错的地方。4.2 用 dpt_depth.py 批量生成深度图参数与运行方式项目里preprocess2.yaml是这一步的配置入口。常见字段包括模型类型、输入图像目录、输出目录、深度范围。如果之前没下载过 DPT 权重第一次运行会自动下载dpt_hybrid或dpt_large权重路径建议写在配置里# configs/preprocess2.yaml input_dir: data/input_images output_dir: data/depth_output model_type: dpt_hybrid max_depth: 200.0运行脚本python preprocess/dpt_depth.py \ --config configs/preprocess2.yaml \ --batch_size 8 \ --fp16model_type决定了模型规模和深度分辨率。dpt_hybrid是速度和精度折中的选择比dpt_large快不少如果对细节要求高比如建筑物墙面上的窗框、幕墙可以考虑dpt_large但显存占用也会上去。max_depth这个参数要按实际航高来设无人机飞行高度 100 米时地面最大深度通常不会超过 150 米设得过大会把深度值拉伸得没有区分度设得过小会截断远处的地形。fp16能减一半显存但对某些 GPU 可能有精度损失先跑几张图对比一下再决定。批量跑完之后dpt_depth.py默认保存为 16 位 PNG 或 npy。16 位 PNG 的好处是可以直接叠加在图像上看npy 则方便后续数值处理。注意这里的深度是单目相对尺度不是米制绝对尺度——这是全项目最容易出现坐标系错乱的地方。项目里scripts/get_depth.py也会从已训练好的 NeRF 模型中提取深度它和 DPT 深度可以互相验证。我的做法是两种深度都生成然后取两者差异不大的区域作为可信区域。4.3 从深度图到三维点、体积和表面重建有了深度图还需要相机内参才能反投影。脚本scripts/get_volume.py和scripts/get_volume_by_surface_reconstruction.py提供的正是这批计算。反投影公式很简单把像素坐标转成相机坐标再乘以深度值。常见实现# scripts/get_volume.py 中单帧深度图转点云的核心逻辑 fx, fy camera_intrinsics[:2] cx, cy camera_intrinsics[2:] v, u np.meshgrid(np.arange(width), np.arange(height)) x (u - cx) / fx * depth y (v - cy) / fy * depth z depth # 将相机坐标系下的点转到世界坐标系 points_cam np.stack([x, y, z], axis-1).reshape(-1, 3) points_world (points_cam R.T t).T这段代码里depth必须和输入图像尺寸一致R、t是当前帧的相机外参。一个常见的错误是直接把 DPT 输出的深度当成米制数据输入这会导致点云整体尺度错误。我一般会先用 COLMAP 稀疏点云里的几个已知点估算一个尺度因子把 DPT 深度缩放到米制单位再进体积计算。具体做法是选取地面上两个已知距离的特征点算出稀疏点云里它们的距离再用 DPT 深度对应位置的像素距离做比值这个比值就是尺度因子。体积计算的逻辑通常是把点云划分到三维体素网格统计每个格子是否被占据然后用体素尺寸乘上占据格子数得到容积。get_volume.py和get_volume2.py的区别我猜一个是用均匀体素一个用高度场的方式近似。对于无人机航拍的大范围地形均匀体素在竖直方向浪费严重get_volume2.py的方案往往更省内存。get_volume_by_surface_reconstruction.py则先做泊松表面重建再通过封闭网格算体积适合建筑物这类有明确表面边界的对象。如果你的目标是土方量估算我建议以表面重建的结果为准体素方法当成快速验证。4.4 从重建结果导出正射投影为什么不能直接把渲染图当地图项目里有一份scripts/get_orthographic_by_arcgis.ipynb专门用来生成正射投影。正射投影的意思是消除透视畸变让平面图的比例尺统一像地图一样可以直接量距离。无人机航拍图本身是中心投影楼顶和楼底在图像上的位置会随视角偏移直接拿某一张航拍图标注地物是不准的。正确做法是把三维重建的结果投影到一个固定的地平面通常是大地坐标系的水平面。这个 notebook 里会读取重建点云或深度图根据相机位姿把每个三维点投影到平面网格再把颜色填进去。如果配合 ArcGIS 使用可以设置输出坐标系和分辨率。我一般会在生成正射影像之前先用前面算好的 ATE 值确认位姿精度再决定这个正射影像能否用于测量。正射投影对尺度因子和绝对坐标要求非常高如果你的 COLMAP 模型没有经过地理配准输出只能叫“相对正射影像”不能直接和真实地图叠加。这一点在工程项目交付前必须跟需求方说清楚。5. 避坑无人机航拍三维重建最常见的坑与排查思路5.1 特征点不足或匹配失败现象COLMAP 跑完稀疏点云只有零星几个点或者直接报No good pair of images。输出的位姿文件里大量相机位姿是空的。原因航拍影像重叠率不够相邻两张图共同可见的特征太少或者场景纹理重复像大片草地、水面、沥青路面SIFT 特征都长得差不多匹配时产生了大量误匹配视频抽帧后还可能出现运动模糊尤其是低空快速飞行时。解决先把重叠率提上来。航向重叠率建议不低于 70%旁向重叠率不低于 60%这是航空摄影测量的经验值。抽帧间隔不要贪多我用ffmpeg抽完帧后会随机挑相邻三张图用 COLMAP 的匹配可视化看一遍特征连线。如果是纹理重复场景换成superpointsuperglue这类学习型特征会比 SIFT 好不少。另外exhaustive_matcher虽然慢但能兜住闭环sequential_matcher会漏掉掉头后的回环导致轨迹漂移这点在无人机航线里尤其明显。5.2 模型飘层和曲面畸变现象NeRF 训练完渲染出来的新视角里地面像被揉过的报纸一样高低起伏墙面有飘在半空的一层薄雾。点云剖切面也明显分成上下两层。原因第一怀疑对象是相机位姿。SfM 出来的位姿存在尺度漂移特别是航线长、闭环少的时候后端位姿越飘越远。NeRF 对这种误差极其敏感位姿误差超过一定范围体密度场会分裂成多层。第二个原因是场景里有动态物体比如移动的车辆、飘动的树它们会被当成静态场景的一部分叠加出半透明的伪影。解决我一般会先把vis_cam_traj.py生成的轨迹画出来看有没有突然的跳变。如果轨迹平滑但重建仍飘就把eval_poses.py打开让 NeRF 在训练过程中对位姿做精化。这个脚本会单独优化前几轮选定的关键帧位姿能救回一部分 SfM 的误差。还有一个笨办法直接把漂移最明显的那几帧从训练集里删掉重新跑一次 SfM。删帧比重建快得多值得先试。5.3 深度图与 RGB 未对齐彩色点云重影现象把 DPT 深度图反投影到三位再叠加 RGB 颜色后会发现建筑物边缘有红绿蓝三色重影像是印刷没套准。原因DPT 输出的深度图尺寸和输入 RGB 图不一致或者深度图和 RGB 图经过了不同的缩放。还有一个常见原因是使用了畸变较大的广角镜头COLMAP 用SIMPLE_RADIAL模型做了去畸变但 DPT 用的是原始畸变图像两边像素坐标对不上。解决先强制把深度图 resize 到和 RGB 完全一致再对齐内参矩阵。更靠谱的做法是在送入 DPT 之前先用 COLMAP 的失真参数把原图去畸变得到和重建一致的校正图DPT 输入校正图输出的深度图就和位姿文件里的intrinsics天然对齐。我自己的习惯是每生成完一帧深度图立刻在 notebook 里叠加 RGB 做一次视觉检查边缘错位超过两个像素就停下来查不要等全部跑完再回头找哪一帧出了问题。5.4 ATE 评估结果几十米但重建看起来没问题现象comp_ate.py跑出的 ATE 误差超过 20 米但 NeRF 渲染出来的新视角视觉质量还行没有明显撕裂。原因大概率是坐标系和尺度没有对齐。COLMAP 的轨迹在一个任意尺度下真实轨迹如果有 GPS 记录通常是在经纬度或 UTM 坐标系里。两者原点不同、尺度不同直接相减当然会得到巨大的误差。还有一个原因是估计轨迹和真实轨迹的时间戳没有对应上导致帧配对错位。解决评估前一定先做 Sim(3) 对齐也就是旋转、平移、尺度都作为自由参数做最优拟合。项目里align_utils.py已经封装好了命令行里不要漏写--align sim3。另外检查两边的轨迹文件是不是同一个起点如果不是可以先按时间戳截取公共段。对齐之后再评估如果 ATE RMSE 仍然超过 1 米才说明位姿解算真的有问题。5.5 训练时显存溢出batch_size 必须调到 1 才能跑现象NeRF 训练刚开始报CUDA out of memory代码里默认的 batch_size1 也救不回来。原因显存爆炸通常不是 batch_size 造成的而是单条光线上的采样点太多。无人机航拍图分辨率高近远边界跨度大粗网络加细网络每条光线要采样近 200 个点每个点都要经过 MLP 前向计算。如果输入图像没有缩到位姿文件对应的尺度scale_factor设为 1 时一张 4000 像素宽的图会直接挤爆显存。解决先把图像分辨率降下来。项目default.yaml里的scale_factor设为 2 或 4让最大边降到 2000 以内。然后把近远边界缩短只保留实际场景范围这个在config.py里可以设。最后再考虑混合精度训练eval_images.py里已经留了 fp16 的接口。如果还是不行就把训练帧数从几百帧降到几十帧先验证流程。记住无人机航拍场景不是帧数越多越好帧数多但位姿误差大的数据还不如用少而精的帧集。6. 进阶用正射投影和轨迹可视化验收重建结果6.1 用轨迹可视化快速发现位姿跳变项目里utils_poses/vis_cam_traj.py可以把估计轨迹和真实轨迹画到同一张图里。这个工具在最终验收时很有用因为 ATE 只是一个数值数值相同的情况下误差可能是均匀散布的也可能是集中在某一段航线上的。只有把轨迹画出来才能分辨。python utils_poses/vis_cam_traj.py \ --est model_output/pred_traj.txt \ --gt data/gt_traj.txt \ --save results/traj_compare.png生成图后我会先看整体形态是否重合。如果估计轨迹和真实轨迹在转弯处有明显偏移说明那一带的特征匹配出了问题如果整体都有系统性偏移但相对形状一致说明只是坐标系没对齐。前者需要回到 SfM 补匹配后者直接做 Sim(3) 对齐就行。这个可视化步骤应该成为每次重建完之后的固定操作。6.2 用正射投影叠图完成最终交付正射投影是工程验收里最直观的产物。把get_orthographic_by_arcgis.ipynb输出的正射影像导入 GIS 软件和卫星底图叠加能直接看出重建有没有变形、比例尺对不对。如果是对比同一工地不同日期的航拍数据还可以做差分对比观察施工进度。我在这个项目里吃过一次亏当时把 NeRF 渲染图当成了正射影像交付结果现场用 RTK 测量几个地面点误差超过 3 米。后来才意识到NeRF 渲染图只是某个视角的透视投影不是真正消除透视畸变的正射图。从那以后我每次做完无人机航拍重建都强制走一遍“SfM 位姿 → ATE 评估 → 轨迹可视化 → 正射投影验证”这条流程再也不跳步骤。希望这份源码拆解能帮你省下我当年踩坑的时间把你的三维重建项目从“能跑”推进到“能验收”。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?