news 2026/9/26 3:18:12

恶劣天气室外三维重建实战:高斯Splatting全流程与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
恶劣天气室外三维重建实战:高斯Splatting全流程与避坑指南

简介:本资源面向计算机视觉与三维重建方向的研究者、开发者及高年级学生,提供一套在雨、雾、雪等恶劣天气条件下实现室外场景三维重建的完整项目实战包。核心采用高斯Splatting算法,通过高斯核函数的平滑与插值处理,有效抑制天气元素对图像质量的干扰,提升重建模型的精度与稳定性,可应用于城市规划、交通监控、环境监测及灾害现场快速建模等场景。压缩包共37个文件,约3MB,以24个Python源码文件为主体,涵盖训练、渲染、损失计算、相机与数据集读取等模块,另含9张png效果图、yml环境配置、sh运行脚本及md说明文档,目录结构清晰,便于按模块查阅与复现。目前已有275人学习下载。读者可获得可直接运行的算法源码、从数据采集到模型输出的流程教程,以及针对恶劣天气的排错与调参思路,适合作为三维重建进阶学习与项目落地的参考。

1. 恶劣天气下室外三维重建:高斯Splatting为什么值得你花时间

雨雾天气拍一圈室外场景,拿回来看照片挺清楚,一跑传统摄影测量或者 NeRF 就露馅:雨丝被当成高频纹理、雾让远景对比度塌掉、地面反光让匹配点飘。高斯Splatting(3D Gaussian Splatting)这两年在三维重建圈子里热度很高,核心原因是它把场景表示成一堆带位置、协方差、颜色和透明度的三维高斯球,用光栅化而不是体渲染来出图,训练和渲染都快了一个量级。但把高斯Splatting直接套到恶劣天气的室外场景上,你会发现它并不天然抗雨抗雾——它只是把重建速度提上来了,鲁棒性还得自己补。这篇要讲的就是:在雨、雾、弱光这类室外条件下,怎么用高斯Splatting搭出一条能跑通、能复现、效果还能看的三维重建流程,从数据采集、预处理、训练参数到排错,一步步落到命令和代码上。适合已经跑过原始3DGS、想把它推到真实室外场景的从业者,也适合刚接触三维重建、想找一个完整实战方向入手的新手。源码和流程教程我会按常见工程做法拆开讲,重点放在“为什么这么设”和“哪里会翻车”。

2. 高斯Splatting在恶劣天气下的原理与选型:为什么不是直接上NeRF

2.1 高斯Splatting的表示与渲染机制

高斯Splatting把场景显式表示为一组三维高斯分布。每个高斯有均值 μ(三维位置)、协方差 Σ(决定椭球形状和朝向)、不透明度 α,以及球谐系数(SH)表示视角相关的颜色。渲染时把这些高斯投影到图像平面,按深度排序做 alpha 混合,得到像素颜色。和 NeRF 的隐式 MLP 不同,它是显式点云式的表示,梯度直接作用在高斯参数上,收敛快、渲染快。

协方差矩阵通常拆成 Σ = R S Sᵀ Rᵀ,R 是旋转四元数,S 是缩放对角阵。这样优化时能保证 Σ 半正定。球谐系数一般用 3 阶,共 16 个系数,能表达一定的高光变化。这套表示对室外场景的适配点在于:它不依赖稠密体采样,对纹理弱、对比度低的区域(雾天远景)不会像 NeRF 那样因为采样不足直接糊掉,但前提是初始点云得靠谱。

2.2 恶劣天气给重建带来的三类退化

雨、雾、弱光对重建的破坏可以归成三类。第一类是高频噪声注入:雨丝、雨滴在图像上是随机亮线,SfM 会把这些当特征点,导致位姿估计抖动。第二类是低频对比度衰减:雾和霾让远处物体对比度下降,暗通道先验失效,深度估计偏浅。第三类是光照不一致:雨天云层散射光让同一物体在不同视角下颜色差异大,球谐系数拟合会过拟合到某几个视角。

这三类退化里,第一类靠预处理能压住大半,第二类需要深度先验或去雾补偿,第三类只能靠训练时的正则和视角均衡。选高斯Splatting而不是 NeRF,主要看中它的训练速度——室外场景动辄几百张图,NeRF 训几天,3DGS 几十分钟到几小时能出结果,迭代调参的成本低得多。但代价是它对初始点云和位姿精度更敏感,位姿一飘,高斯球就散成一片。

2.3 整体流程与工具链选型

常见做法是:COLMAP 做 SfM 拿位姿和稀疏点云 → 预处理去雨去雾 → 用稀疏点云初始化高斯 → 训练 3DGS → 导出 ply 做后处理。工具链上,3DGS 官方实现(graphdeco-inria/gaussian-splatting)是基线,室外场景建议配一个去雨网络(如 Restormer 或 MPRNet 的预训练权重)和去雾模块(暗通道或 AOD-Net)。COLMAP 用 3.8 以上版本,CUDA 11.8 配 PyTorch 2.0 以上比较稳。

提示:不要一上来就换自定义 CUDA 算子,先把官方实现跑通,确认位姿和点云没问题,再动渲染管线。

3. 数据采集与预处理:把雨雾从输入里剥掉

3.1 采集参数与拍摄策略

室外恶劣天气采集,核心是保证重叠率和曝光一致。建议相邻视角重叠 70% 以上,绕场景走两圈,一圈平视一圈略俯,避免只拍一个高度导致高斯球在垂直方向塌陷。曝光用手动模式,固定 ISO 和快门,避免自动曝光让不同帧亮度跳变。雨天拍摄尽量选雨势小的间隙,或者用偏振镜压掉部分反光。分辨率不要超过 1920×1080,太高 COLMAP 匹配慢且容易过拟合噪声。

如果只能拍到雨雾很重的素材,采集时多拍近景细节,远景靠去雾补。快门速度建议 1/250 以上,减少雨丝拖影。每张照片记录 GPS 或至少记录拍摄顺序,方便后续检查位姿连续性。

3.2 去雨去雾预处理脚本

预处理用 Python 调预训练模型,下面是一个去雨的最小示例,基于 Restormer 的推理接口(实际使用时替换成你本地权重路径)。

import torch import cv2 import numpy as np from restormer import Restormer # 假设已按官方仓库搭好模型定义 # 加载去雨权重,权重文件放本地,不要在线拉 model = Restormer() state = torch.load("./weights/restormer_derain.pth", map_location="cpu") model.load_state_dict(state) model = model.cuda().eval() def derain_image(img_path, out_path): img = cv2.imread(img_path) # BGR img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) tensor = torch.from_numpy(img).float().permute(2,0,1).unsqueeze(0) / 255.0 tensor = tensor.cuda() with torch.no_grad(): out = model(tensor) # 输出同尺寸 out = out.squeeze(0).permute(1,2,0).cpu().numpy() out = np.clip(out * 255.0, 0, 255).astype(np.uint8) cv2.imwrite(out_path, cv2.cvtColor(out, cv2.COLOR_RGB2BGR)) if __name__ == "__main__": derain_image("./raw/frame_001.jpg", "./clean/frame_001.jpg")

这段代码的逻辑是:读图转 RGB、归一化到 [0,1]、送进网络、输出再转回 uint8 存盘。参数上,输入尺寸建议保持原图,Restormer 对尺寸不敏感但太大显存吃紧,可以切成 512×512 的块再拼。去雾可以用暗通道先验做快速版,或者 AOD-Net,暗通道的窗口半径设 15、omega 设 0.95 是常用值。

注意:去雨去雾会引入伪影,如果伪影比雨本身还重,宁可不去,靠训练时的鲁棒损失扛。预处理后一定要人工抽检 10% 的图,确认没有把细节抹掉。

3.3 COLMAP位姿估计与稀疏点云导出

预处理完的图送 COLMAP。命令行流程如下:

colmap feature_extractor \ --database_path ./colmap/database.db \ --image_path ./clean \ --ImageReader.single_camera 1 \ --SiftExtraction.max_num_features 8192 colmap exhaustive_matcher \ --database_path ./colmap/database.db \ --SiftMatching.guided_matching 1 colmap mapper \ --database_path ./colmap/database.db \ --image_path ./clean \ --output_path ./colmap/sparse colmap model_converter \ --input_path ./colmap/sparse/0 \ --output_path ./colmap/sparse/0/points.ply \ --output_type PLY

single_camera 1表示所有图共用内参,室外同一设备拍摄时开这个能减少自由度。max_num_features 8192提高特征数,雾天纹理弱时有用。guided_matching 1在匹配阶段用几何引导,能压掉一部分雨丝造成的误匹配。mapper 输出后检查sparse/0里的相机数和注册率,注册率低于 80% 说明位姿估计有问题,回去查重叠率和去雨效果。

4. 训练高斯Splatting:参数怎么设、损失怎么调

4.1 从稀疏点云初始化高斯

3DGS 官方实现用 COLMAP 的稀疏点云初始化高斯位置,颜色用 SH 的 0 阶(即 RGB 均值)初始化,缩放用最近邻距离估计。室外场景点云稀疏,建议把初始点云做一次统计滤波去掉离群点,否则离群点会变成漂浮的高斯球。

import open3d as o3d pcd = o3d.io.read_point_cloud("./colmap/sparse/0/points.ply") # 统计滤波:每个点看 20 个邻居,标准差倍数 2.0 cl, ind = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0) o3d.io.write_point_cloud("./colmap/sparse/0/points_filtered.ply", cl)

nb_neighbors设 20 是平衡速度和效果,点云大可以降到 10。std_ratio越小去得越狠,2.0 是常用起点,雾天点云噪声大可以降到 1.5。滤波后点数会掉 10% 到 30%,正常。

4.2 训练命令与关键参数

官方训练入口是train.py,室外场景常用参数如下:

python train.py \ -s ./data/outdoor_rain \ -m ./output/outdoor_rain \ --iterations 30000 \ --position_lr_init 0.00016 \ --position_lr_final 0.0000016 \ --densify_until_iter 15000 \ --densify_grad_threshold 0.0002 \ --opacity_reset_interval 3000 \ --white_background 0

iterations 30000是官方默认,室外场景可以加到 40000 但收益递减。position_lr_init和final控制高斯位置学习率,室外大场景可以适当调大初始值加快收敛。densify_until_iter 15000表示 15000 步后停止增密,雾天噪声多的话可以提前到 10000,避免高斯球被噪声撑爆。densify_grad_threshold是增密梯度阈值,调小会增更多高斯,显存吃紧就调大。opacity_reset_interval 3000定期重置不透明度,防止高斯球在雾区堆积。

提示:white_background 0在室外场景必须设 0,否则背景会被当成白色,天空区域重建会发灰。

4.3 针对雨雾的损失与正则调整

官方损失是 L1 加 D-SSIM,权重 0.8 和 0.2。恶劣天气下建议加两项:一是对远景区域加深度平滑正则,二是对高不透明度高斯加稀疏正则。深度平滑可以用 COLMAP 的稀疏深度做弱监督,稀疏正则直接对 α 加 L1。

# 在 train.py 的 loss 计算处插入 loss_l1 = l1_loss(rendered, gt) loss_dssim = 1.0 - ssim(rendered, gt) loss_sparse = 1e-4 * torch.mean(torch.abs(gaussians.get_opacity)) total_loss = 0.8 * loss_l1 + 0.2 * loss_dssim + loss_sparse

1e-4是稀疏正则权重,太大会让高斯球变透明导致画面发虚,建议从 1e-5 试起。深度平滑需要额外读 COLMAP 深度图,实现复杂,如果位姿够准可以跳过。训练时盯loss曲线,如果 5000 步后还在 0.1 以上,多半是位姿或去雨没做好。

5. 避坑与排查:室外恶劣天气重建的五个血泪教训

5.1 现象:高斯球在雾区糊成一团,远景全白

原因:雾天图像对比度低,COLMAP 在远景匹配不到足够特征点,稀疏点云在远处几乎为空,高斯球只能靠增密硬撑,结果在雾区堆出一片低透明度高斯。解决:去雾预处理必须做,且去雾后重新跑 COLMAP;训练时把densify_until_iter降到 10000,减少雾区增密;必要时手动在远景补一些点云。

5.2 现象:雨丝被重建成立体线条,画面出现悬浮细丝

原因:去雨不彻底,残留雨丝在 SfM 里被当成特征,生成对应的高斯球。解决:去雨网络换更强的权重,或者对去雨后图像做一次中值滤波(3×3)压掉细线;COLMAP 匹配时开guided_matching并提高max_num_features,让真实特征压过雨丝。

5.3 现象:训练到 10000 步后 loss 突然跳升,画面出现大片黑斑

原因:opacity_reset_interval触发时,部分高斯球不透明度被重置,如果此时增密还在进行,新老高斯混在一起导致渲染不稳定。解决:把opacity_reset_interval设成 5000 或干脆关掉(设很大),等增密结束后再重置;或者把densify_until_iter和重置间隔错开。

5.4 现象:同一场景不同视角颜色差异大,球谐系数过拟合

原因:雨天光照不一致,球谐系数为了拟合每个视角的颜色,把高频变化学进去了,换视角就崩。解决:降低球谐阶数到 1 阶或 0 阶,牺牲一点视角相关效果换稳定性;训练时对颜色加 TV 正则,或者把曝光不一致的帧剔除。

5.5 现象:显存爆掉,训练到一半 OOM

原因:室外场景高斯数量容易冲到几百万,加上去雨模型占显存。解决:训练前把去雨模型挪到 CPU 或单独跑;3DGS 训练时把densify_grad_threshold调大(如 0.0004),限制高斯数量;分辨率降到 1600×900 以下;用--resolution 2降采样。

6. 进阶技巧:用深度先验和分块训练把室外场景做扎实

室外恶劣天气重建想再上一个台阶,单靠 3DGS 官方管线不够,得补深度先验和分块策略。深度先验可以用单目深度估计模型(如 Depth Anything 或 MiDaS)生成稠密深度图,和 COLMAP 稀疏深度做一致性检查,把不一致的区域标记出来,训练时对这些区域降权。具体做法是:对每张图跑深度估计,得到相对深度,再用 COLMAP 的稀疏点做尺度对齐,对齐后算每个像素的深度置信度,置信度低于阈值的像素在 L1 损失里乘 0.3。

分块训练针对大场景。把场景按 COLMAP 相机位置聚成若干块,每块单独训一个 3DGS,最后用块间重叠区域做对齐合并。合并时用 ICP 对齐点云,再统一球谐系数。这样单块显存可控,且每块可以单独调参。分块数量按场景大小定,一般 4 到 8 块,块间重叠 20% 以上。

验证方法上,除了看 PSNR/SSIM,室外场景更该看几何一致性:用留出的测试视角渲染深度图,和激光或深度先验比,看边缘是否对齐。我一般会抽 5 个视角做人工检查,重点看地面和建筑边缘有没有漂浮高斯。

下面是一个深度置信度加权的损失片段:

# depth_prior: 单目深度对齐后的深度图, conf: 置信度图 def weighted_l1(rendered, gt, conf): diff = torch.abs(rendered - gt) return torch.mean(diff * conf) # conf 低于阈值的像素权重已置 0.3 loss = weighted_l1(rendered, gt, conf) + 0.2 * (1.0 - ssim(rendered, gt))

conf的生成是关键,对齐尺度用最小二乘拟合scale * mono_depth + shift = sparse_depth,拟合残差大的像素置信度低。这套做法我踩过的坑是:单目深度在雾天本身就不准,置信度会整体偏低,这时候阈值要放宽,否则有效像素太少,损失没梯度。

最后说个习惯:每次改完预处理或训练参数,先跑 3000 步看 loss 和渲染图,别一上来就 30000 步,省下来的时间够你多试三组参数。室外恶劣天气重建没有银弹,去雨、去雾、位姿、增密、正则,每个环节都得盯。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 3:18:03

AI短剧工业化流水线:6步可落地的全流程生产方法论

1. 这不是“AI视频课”,而是一套可落地的短剧工业化流水线最近在B站刷到一个标题特别扎眼的教程:“【LibTV教程】目前B站最详细的一站式制作教程!从剧本、分镜、人物生成、视频、配音到剪辑完整演示,零基础手把手操作,…

作者头像 李华
网站建设 2026/9/26 3:16:08

MySQL四大NULL处理函数实战指南:IF、IFNULL、NULLIF、ISNULL深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 3:15:20

MWORKS物理建模:破解RLC谐振与信号调理的工程失真

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 3:14:58

医学影像多标签文本分类实战解析与 Kaggle 入门建模

这道 Kaggle 案例虽然平台元数据极少,但任务形态很适合作为多标签文本分类的完整练习。文章重点不放在题面信息本身,而是放在如何从稀缺说明中还原任务结构,识别文本字段与标签组织方式,并建立可提交、可验证、可迭代的分类流程。 多标签文本分类在医疗场景并不只是竞赛练…

作者头像 李华
网站建设 2026/9/26 3:14:58

Testing Classification实战复盘 多标签文本分类从基线建模到提交流程

这道 Kaggle 练习赛虽然题面极简,但任务指向很明确,核心是围绕多标签文本分类搭建一条完整可运行的建模链路。真正有价值的部分不在排行榜,而在于把文本字段、标签矩阵、验证方式、预测输出和提交格式衔接起来,形成可复用的分类原型。 从技术实战角度看,这类小规模赛题很…

作者头像 李华