☰
无人机航拍三维重建Python源码实战:COLMAP位姿与NeRF深度图
2026/10/12 15:59:11 网站建设 项目流程

简介:本资源面向计算机、人工智能、自动化等专业的在校学生与开发者,提供一套基于无人机航拍数据的三维场景重建完整项目源码,可用于毕业设计、课程大作业或项目初期立项演示。项目围绕多角度地面图像采集、COLMAP位姿估计与Behindthescenes深度图生成构建数据集,并给出训练与测试脚本,覆盖数据预处理、模型训练、位姿评估与三维渲染等环节。压缩包共54个文件,以41个Python源码为核心,辅以3个yaml配置、2个ipynb笔记本、2个txt说明及png、mp4、gif等可视化结果,整体约20.65MB,目录结构清晰,便于按模块阅读与二次开发。目前已有776人学习下载。读者可据此掌握从航拍数据到三维重建的完整流程,理解深度估计、轨迹对齐与ATE评估等关键实现,并可在现有代码基础上修改扩展,完成自己的课题或作业。

1. 无人机航拍三维重建:从一份能跑通的 Python 源码包说起

手头有一批无人机航拍图,想重建出带纹理的三维场景,还要能算体积、出正射影像,这事听起来像要攒一整套摄影测量流水线。实际上这份「基于无人机航拍数据的三维场景重建 python 源码 + 项目说明 + 无人机数据集.zip」把链路拆得比较清楚:用 COLMAP 估位姿当基准,用 Behind the Scenes 那套思路拿深度图,再喂给一个带畸变建模的 NeRF 类网络训练,最后在 evaluation 和 scripts 里做位姿误差、正射投影、体积计算。它适合计算机、人工智能、自动化方向的在校生做毕业设计或课程大作业,也适合想快速摸清「航拍图怎么变成三维场景」这条链路的工程师。下面按我拆包复现的顺序讲,重点放在参数、命令和那些不跑一遍根本不知道的坑上。

2. 拆包先看结构:数据流、模块划分与依赖关系

2.1 目录里藏着一条完整流水线

把压缩包解开,根目录大致分四块。第一块是轨迹评估工具:align_trajectory.py、transformations.py、trajectory_utils.py、align_utils.py、compute_trajectory_errors.py、results_writer.py,这几个文件配合utils_poses/lie_group_helper.py、vis_cam_traj.py、align_traj.py、comp_ate.py,负责把估计轨迹和 COLMAP 基准对齐并算 ATE。第二块是数据预处理:preprocess/dpt_depth.ipynb、dpt_depth.py、get_log_to_txt.py,以及configs/Tanks/wurenji.yaml、preprocess2.yaml、default.yaml。第三块是模型本体:model/下的network.py、training.py、losses.py、distortions.py、intrinsics.py、poses.py、official_nerf.py、rendering.py、checkpoints.py、extracting_images.py、eval_images.py、eval_pose_one_epoch.py,加上dataloading/的dataset.py、dataloading.py、common.py、configloading.py。第四块是评估与脚本:evaluation/eval.py、eval_poses.py,scripts/下的get_orthographic_by_arcgis.ipynb、get_depth.py、get_volume.py、get_volume2.py、get_matrix_by_sfm.py、get_volume_by_surface_reconstruction.py。third_party/pytorch_ssim是图像质量评估依赖,results/里放了wuren_test.png、wurenji_small_resolution.mp4、正射投影.png、mountain2.gif、gaoqing.mp4这些结果样例。

这条链路的核心逻辑是:COLMAP 给出相机内外参作为「真值基准」,Behind the Scenes 风格的方法从航拍图里估计深度,网络在训练时同时优化颜色和深度,最后用轨迹对齐脚本量化位姿精度。理解了这个数据流,后面调参和排错才有方向。

2.2 环境依赖与版本约束

项目是纯 Python 实现,深度学习部分依赖 PyTorch,图像和位姿处理依赖 NumPy、OpenCV、SciPy,SSIM 用的是third_party里自带的 pytorch_ssim。dpt_depth.py用到了 DPT 深度估计模型,需要单独装对应权重。常见做法是建一个干净的 conda 环境,Python 3.8 到 3.10 之间比较稳,PyTorch 选 1.12 以上带 CUDA 的版本。装依赖时先把torch、torchvision按官方命令装好,再补numpy、opencv-python、scipy、matplotlib、tqdm、pyyaml。pytorch_ssim不用 pip 装,直接把third_party/pytorch_ssim加进sys.path或按项目里的 import 路径引用即可。

# 建环境,Python 版本别太新,3.8~3.10 兼容性最好 conda create -n uav3d python=3.9 -y conda activate uav3d # 按自己 CUDA 版本装 PyTorch,这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 其余依赖 pip install numpy opencv-python scipy matplotlib tqdm pyyaml

参数说明:python=3.9是经验值,太新的 3.12 容易在编译扩展时翻车;PyTorch 的 index-url 要和自己显卡驱动匹配,装完用python -c "import torch; print(torch.cuda.is_available())"验证,返回True才算通。这一步不通,后面训练全是 CPU 硬扛,基本没法看。

2.3 配置文件怎么读

configs/Tanks/wurenji.yaml是主训练配置,preprocess2.yaml管预处理,default.yaml是默认参数底座。打开wurenji.yaml,重点看几个字段:数据根目录、图像分辨率、训练轮数、学习率、深度损失权重、畸变参数开关。dataloading/configloading.py负责把这些 yaml 解析成运行时对象,dataloading/common.py里通常放着路径拼接和数据集划分逻辑。改配置时不要直接动default.yaml,在wurenji.yaml里覆盖对应键,这样换数据集时只改一个文件。

提示:yaml 对缩进敏感,用空格不要用 Tab,改完先用python -c "import yaml; yaml.safe_load(open('configs/Tanks/wurenji.yaml'))"过一遍语法,能省掉很多「配置没生效」的玄学排查。

3. 数据准备与预处理:COLMAP 位姿、深度图与数据集组织

3.1 用 COLMAP 估位姿作为训练基准

项目说明里写得很直白:先拿地面多角度图片,用 COLMAP 估计位姿,作为模型训练的一个基准。这一步是整个重建的地基,位姿不准,后面网络再强也白搭。常见做法是把航拍图按images/放好,跑 COLMAP 的 feature extractor、matcher 和 mapper,导出cameras.txt、images.txt、points3D.txt。项目里scripts/get_matrix_by_sfm.py就是用来从 SfM 结果里提取相机矩阵的,utils_poses/lie_group_helper.py则提供李群李代数转换,方便后续对齐。

# COLMAP 命令行典型流程,具体路径按自己数据改 colmap feature_extractor \ --database_path ./colmap.db \ --image_path ./images \ --ImageReader.single_camera 1 colmap exhaustive_matcher --database_path ./colmap.db colmap mapper \ --database_path ./colmap.db \ --image_path ./images \ --output_path ./sparse

参数说明:--ImageReader.single_camera 1表示所有图共用一台相机内参,无人机同一镜头拍的一般都这么设;exhaustive_matcher适合图片数量不多(几百张以内)的情况,图多了换成sequential_matcher更快。跑完检查sparse/0/下三个 txt 是否齐全,points3D.txt点数太少说明匹配质量差,得回头看看是不是重叠度不够或者光照变化太大。

3.2 Behind the Scenes 思路拿深度图

项目说明提到「通过 Behind the Scenes 算法来获得航拍图像的深度图」,对应代码在preprocess/dpt_depth.py和dpt_depth.ipynb。DPT 是密集预测 Transformer,用来做单目深度估计,输出和原图同分辨率的深度图。get_log_to_txt.py负责把训练日志转成文本,方便记录。深度图的质量直接决定网络学到的几何是否合理,所以这一步别图快,分辨率尽量保持原图级别。

# preprocess/dpt_depth.py 的核心调用逻辑(示意,按实际接口调整) import torch from dpt_depth import load_dpt_model, infer_depth model = load_dpt_model(ckpt_path="weights/dpt_hybrid.pth", device="cuda") depth = infer_depth(model, image_path="images/0001.jpg", target_size=(1080, 1920)) # depth 是归一化后的相对深度,保存时按项目约定命名 save_depth(depth, "depths/0001.npy")

逻辑说明:load_dpt_model加载 DPT 权重,infer_depth做前向推理并把输出 resize 回原图尺寸。参数上target_size要和训练配置里的分辨率一致,否则深度图和 RGB 对不齐,训练时 loss 会异常震荡。保存格式项目里用的是.npy,方便dataloading/dataset.py直接np.load读取。

3.3 数据集目录组织与划分

无人机数据集(含深度图)按项目说明是单独放在网盘里的,下载后要和代码里的路径对上。典型组织方式是:data/wurenji/images/放原图,data/wurenji/depths/放深度图,data/wurenji/sparse/放 COLMAP 结果,data/wurenji/poses/放提取好的位姿。dataloading/dataset.py会按配置里的data_root去拼这些子目录,dataloading/common.py里通常有 train/val 划分逻辑。

目录内容对应代码
images/航拍原图dataset.py 读取 RGB
depths/DPT 深度图 .npydataset.py 读取深度监督
sparse/COLMAP 三个 txtget_matrix_by_sfm.py 解析
poses/提取后的位姿矩阵poses.py 加载

注意:路径里尽量别带中文和空格,Windows 下解压出来的中文目录名经常让cv2.imread返回 None,排查半天以为是代码问题,其实是路径编码的锅。

4. 训练与评估:train.py 跑通、eval.py 验证与 ATE 对齐

4.1 启动训练与关键参数

项目说明给的训练命令是python train.py configs/Tanks/wurenji.yaml。train.py会读配置、建 dataset、实例化model/network.py里的网络、挂上model/losses.py的损失,然后进model/training.py的训练循环。model/distortions.py处理镜头畸变,model/intrinsics.py管内参,model/poses.py管位姿,model/rendering.py做体渲染,model/checkpoints.py负责存盘。

# 训练,建议先小分辨率跑通再放大 python train.py configs/Tanks/wurenji.yaml # 训练日志会写到 loss.txt,方便画曲线 tail -f loss.txt

参数说明:配置里learning_rate一般从 5e-4 起,太大 loss 直接飞,太小收敛慢到怀疑人生;num_epochs看数据量,几百张图通常几十到上百轮;深度损失权重depth_loss_weight是调重建几何质量的关键,调大几何更准但颜色可能发糊,调小反之。loss.txt和psnr.txt是项目自带的日志文件,训练时会被追加写入,用matplotlib画出来能直观看到收敛情况。

4.2 测试与图像质量评估

训练完按项目说明跑python evaluation/eval.py configs/Tanks/wurenji.yaml。evaluation/eval.py会加载 checkpoint,在测试视角上渲染图像,eval_images.py算 PSNR 和 SSIM,eval_poses.py和eval_pose_one_epoch.py评估位姿精度。third_party/pytorch_ssim在这里派上用场。results/里的wuren_test.png、wurenji_small_resolution.mp4就是渲染结果样例,可以拿来和自己跑出来的对比。

# evaluation/eval.py 里图像指标计算的核心逻辑(示意) from third_party.pytorch_ssim import ssim import torch def compute_metrics(rendered, gt): mse = torch.mean((rendered - gt) ** 2) psnr = 10 * torch.log10(1.0 / mse) ssim_val = ssim(rendered.unsqueeze(0), gt.unsqueeze(0)) return psnr.item(), ssim_val.item()

逻辑说明:PSNR 基于 MSE 算,对亮度敏感;SSIM 看结构相似度,更贴近人眼。两个指标一起看,PSNR 高但 SSIM 低,往往是渲染整体偏亮或偏暗但结构还行。参数上注意输入要归一化到 [0,1],否则 PSNR 数值会离谱。

4.3 轨迹对齐与 ATE 计算

这是这个项目比较硬核的一块。align_trajectory.py、align_utils.py、trajectory_utils.py、compute_trajectory_errors.py、results_writer.py配合utils_poses/align_traj.py、comp_ate.py,把网络估计的相机轨迹和 COLMAP 基准对齐,算绝对轨迹误差 ATE。transformations.py提供四元数、旋转矩阵、欧拉角互转,lie_group_helper.py提供 SE3 上的操作。

# 对齐轨迹并算 ATE python align_trajectory.py \ --est_poses poses/estimated.txt \ --gt_poses poses/colmap_gt.txt \ --output results/ate_result.txt # 可视化相机轨迹 python utils_poses/vis_cam_traj.py --pose_file poses/estimated.txt

参数说明:--est_poses是网络输出的位姿,--gt_poses是 COLMAP 基准,两者坐标系可能差一个相似变换,align_trajectory.py会先做 Umeyama 对齐再算误差。ATE 的 RMSE 越小越好,一般对齐后能到厘米级说明位姿估计靠谱。vis_cam_traj.py画出来的轨迹图能直观看出估计轨迹和真值是否贴合,results/里的可视化样例可以对照。

5. 避坑与排查:那些不跑一遍不知道的坑

5.1 现象:训练 loss 一直不降,PSNR 卡在十几

原因:最常见是深度图和 RGB 没对齐,或者 COLMAP 位姿坐标系和网络假设的坐标系不一致。dataloading/dataset.py读深度时如果 resize 方式和 RGB 不一致,监督信号就是错的。

解决:先单独可视化一对 RGB 和深度图,确认边缘对齐;再检查poses.py里位姿的坐标系约定(是相机到世界还是世界到相机),和 COLMAP 导出的images.txt对齐。项目里get_matrix_by_sfm.py就是干这个的,别跳过。

5.2 现象:eval.py 报 checkpoint 找不到或 key 不匹配

原因:model/checkpoints.py存盘时的 key 和加载时的网络结构对不上,通常是改了network.py后没重新训练,或者配置里checkpoint_path指到了旧文件。

解决:确认configs/Tanks/wurenji.yaml里的 checkpoint 路径指向最新训练产物,加载时用strict=False先看哪些 key 缺失,缺的是不是关键层。改过网络结构就老老实实重训,别指望旧权重能直接套。

5.3 现象:COLMAP 跑完 points3D 只有几十个点

原因:航拍图重叠度不够,或者exhaustive_matcher在纹理重复区域(比如大片农田、水面)匹配失败。

解决:提高航拍重叠率到 70% 以上,或者换sequential_matcher并调--SequentialMatching.overlap。纹理弱的区域可以先用get_depth.py的深度先验辅助,但根本还是拍摄时保证重叠和纹理。

5.4 现象:scripts 里的体积计算脚本结果离谱

原因:get_volume.py、get_volume2.py、get_volume_by_surface_reconstruction.py依赖重建出的表面网格或点云,如果深度尺度没对齐到真实尺度,体积就是错的。

解决:先用get_matrix_by_sfm.py把尺度对齐到 COLMAP 基准,再跑体积计算。get_orthographic_by_arcgis.ipynb出正射投影时也要确认地理参考,不然正射投影.png那种结果只能看个形状,量不了实际距离。

5.5 现象:显存不够,训练中途 OOM

原因:wurenji.yaml里分辨率设太高,或者 batch size 太大,model/rendering.py的体渲染采样点数多时显存吃得很凶。

解决:先把分辨率降到wurenji_small_resolution.mp4那个级别跑通,再逐步放大;rendering.py里的采样数num_samples和num_importance可以适当调小,用精度换显存。实在不够就减 batch size,梯度累积补回来。

6. 进阶玩法:正射投影、体积计算与结果验证的实操技巧

把训练和评估跑通只是及格线,这份资源真正有意思的是scripts/里那套下游应用。get_orthographic_by_arcgis.ipynb用 ArcGIS 出正射投影,get_volume.py和get_volume2.py算体积,get_volume_by_surface_reconstruction.py走表面重建路线算体积,get_depth.py单独抽深度。我一般会按「先验证几何尺度,再算量」的顺序走,因为体积和正射对尺度误差极其敏感,尺度差 1%,体积就差 3%。

验证方法上,拿results/正射投影.png和results/mountain2.gif当参照,自己跑出来的正射图先叠到原航拍图上,看地物边缘是否重合。重合了再量已知尺寸的地物(比如一段已知长度的跑道或建筑),反推尺度系数。这一步用get_matrix_by_sfm.py输出的矩阵做基准最稳。

# 体积计算前的尺度校验思路(示意) import numpy as np def check_scale(recon_points, known_distance, p1_idx, p2_idx): d_recon = np.linalg.norm(recon_points[p1_idx] - recon_points[p2_idx]) scale = known_distance / d_recon print(f"尺度系数: {scale:.6f}") return scale # 用已知地物两点距离反推尺度,再乘到所有重建点上 scale = check_scale(points, known_distance=50.0, p1_idx=100, p2_idx=250) points_scaled = points * scale

逻辑说明:known_distance是实地量出来的两点距离,p1_idx、p2_idx是重建点云里对应的点索引。算出的scale乘到整个点云上,体积计算才有物理意义。参数上known_distance越准,尺度越可靠,建议选两个在图像里清晰、实地好量的点。

提示:get_volume2.py和get_volume.py的区别通常在积分方式或表面重建策略上,跑之前先看两个脚本的 docstring 或注释,选适合自己数据密度的那版,别两个混着用。

从那以后我每次拿到这类重建结果,都强制先走一遍「尺度校验 → 正射叠图 → 体积复算」三步,少一步后面全是后悔药。这份资源把训练、评估、下游脚本都配齐了,按上面的顺序拆一遍,基本能把无人机航拍三维重建这条链路摸透。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询