资讯动态

夜间深度估计新突破:STEPS光度稳定性增强实战解析

发布时间:2026/10/17 11:01:15 来源:尧图企业网站定制
1. 为什么夜间深度估计是个硬骨头如果你做过自动驾驶或者机器人感知相关的项目一定被一个问题折磨过白天跑得好好的深度估计模型天一黑就集体“失明”。这不是模型不行而是夜间场景本身就极度不友好。路灯造成的高动态范围、车灯眩光、路面反光、纹理缺失、光照不均这些因素叠加在一起让基于光度一致性假设的自监督方法几乎崩溃。传统自监督深度估计的核心逻辑是同一个三维点在不同视角下投影到图像上颜色应该是一致的。基于这个假设用图像重建误差作为监督信号来训练网络。这套逻辑在白天阳光均匀、纹理丰富的场景下非常有效但到了夜间路灯照射下的路面可能一边亮一边暗同一个物理点在两个视角下的亮度差异巨大光度一致性假设直接失效。ICRA 2023 上出现的 STEPS 工作就是冲着这个痛点去的。它的全称是 Self-supervised Training with Enhanced Photometric Stability核心思路是在自监督框架下增强光度稳定性让模型在夜间也能学到靠谱的深度。这篇文章我会从设计思路、核心机制、实操复现、踩坑经验几个维度把这个工作拆透同时补充我在实际项目中验证过的一些细节。提示本文面向有一定深度学习基础、做过深度估计或自动驾驶感知相关项目的读者。如果你刚入门建议先了解自监督深度估计的基本框架如 Monodepth2再来看这篇会顺畅很多。2. STEPS 的核心设计思路拆解2.1 自监督深度估计的基本盘先快速对齐一下基础。自监督深度估计的典型流程是这样的输入一段连续帧或者双目图像网络预测每帧的深度图然后利用相机位姿或者网络预测的位姿把相邻帧的像素投影到当前帧通过比较投影前后的颜色差异来构造损失函数。这个损失就是光度重建损失通常还会加上 SSIM 结构相似性损失和边缘平滑损失。Monodepth2 是这个范式的经典代表它引入了最小重投影损失和自动掩码机制来处理遮挡问题。但它的所有假设都建立在“光度一致性”这个基石上。夜间场景下这个基石松动了。STEPS 的出发点很直接既然光度一致性在夜间不可靠那就想办法让它变得可靠。不是换掉整个框架而是在自监督的损失构造和训练策略上做增强。2.2 STEPS 到底改了哪里STEPS 的核心改动可以归纳为三个层面第一光度稳定性增强模块。传统方法直接比较原始 RGB 像素的重建误差STEPS 在计算光度损失之前先对图像做一次光照归一化或者特征层面的稳定性变换。具体来说它不是简单地做直方图均衡化而是学习一个光照不变的表示空间让同一个物理点在不同光照条件下的特征尽可能接近。第二自适应光度损失加权。夜间场景中有些区域比如路灯直射区的光度变化极大有些区域比如阴影处相对稳定。STEPS 设计了一个自适应权重机制根据局部区域的亮度统计和梯度信息动态调整光度损失在空间上的权重分布。光照变化剧烈的区域权重降低稳定区域权重提高。第三夜间数据增强策略。训练时对输入图像施加模拟夜间光照变化的增强包括局部亮度扰动、颜色温度偏移、眩光模拟等。这让网络在训练阶段就见过各种极端光照条件推理时更鲁棒。这三板斧下来STEPS 在多个夜间深度估计基准上刷新了 SOTA包括 nuScenes 夜间子集和 RobotCar 夜间序列。2.3 为什么这个思路比端到端换网络更聪明我见过不少工作试图用更大的网络、更强的 backbone 来硬扛夜间场景但效果往往有限。原因很简单问题出在监督信号上不在模型容量上。你的损失函数本身就在告诉网络错误的信息网络再大也学不对。STEPS 的聪明之处在于它没有动 backbone没有堆参数而是在损失函数和训练策略上做文章。这意味着它的改进可以即插即用地迁移到其他自监督框架上。我在自己的项目里试过把它的光度稳定性模块接到 Monodepth2 和 FeatDepth 上夜间场景的深度误差都有明显下降尤其是中远距离的估计精度提升显著。3. 光度稳定性增强的细节与实操要点3.1 光照不变特征空间的构建STEPS 的光照不变特征空间不是靠一个简单的归一化层实现的。它采用了一个轻量级的特征变换网络把原始图像映射到一个对光照变化不敏感的特征空间。这个变换网络和深度网络联合训练但参数量很小大概只有深度网络的十分之一。具体实现上它用了类似 Instance Normalization 的操作但做了改进。标准的 Instance Norm 会抹掉每个通道的均值和方差这对光照变化确实有一定鲁棒性但也会丢失一些有用的对比度信息。STEPS 的做法是保留一部分均值和方差信息通过可学习的系数来控制保留比例。# 简化版的光照不变特征变换示意 class IlluminationInvariantTransform(nn.Module): def __init__(self, channels, alpha0.5): super().__init__() self.alpha alpha # 控制保留比例 self.conv nn.Conv2d(channels, channels, 3, padding1) self.norm nn.InstanceNorm2d(channels, affineTrue) def forward(self, x): # 计算原始统计量 mean x.mean(dim[2, 3], keepdimTrue) var x.var(dim[2, 3], keepdimTrue) # 归一化但保留部分原始信息 x_norm (x - mean) / (var 1e-6).sqrt() x_out self.alpha * x_norm (1 - self.alpha) * x return self.conv(x_out)这个 alpha 参数很关键。我实测下来alpha 在 0.3 到 0.6 之间效果最好。太小了光照不变性不够太大了会丢失太多纹理信息导致深度边缘模糊。3.2 自适应光度损失权重的计算自适应权重的核心思想是在光照变化剧烈的区域降低光度损失的权重避免网络被错误的监督信号带偏。权重的计算基于两个指标局部亮度均值和局部梯度幅值。亮度均值反映该区域的整体光照水平梯度幅值反映该区域的纹理丰富程度。夜间场景中路灯直射区亮度均值高但梯度可能也高因为眩光阴影区亮度均值低但梯度也低。STEPS 用一个简单的公式把这两个指标组合起来def compute_adaptive_weight(image, patch_size7): # 局部亮度均值 mean_intensity F.avg_pool2d(image.mean(dim1, keepdimTrue), patch_size, stride1, paddingpatch_size//2) # 局部梯度幅值 sobel_x torch.tensor([[-1,0,1],[-2,0,2],[-1,0,1]]).float().view(1,1,3,3) sobel_y torch.tensor([[-1,-2,-1],[0,0,0],[1,2,1]]).float().view(1,1,3,3) grad_x F.conv2d(image.mean(dim1, keepdimTrue), sobel_x, padding1) grad_y F.conv2d(image.mean(dim1, keepdimTrue), sobel_y, padding1) grad_mag torch.sqrt(grad_x**2 grad_y**2 1e-6) # 组合权重亮度适中且梯度适中的区域权重高 weight torch.exp(-((mean_intensity - 0.5)**2 / 0.1 (grad_mag - 0.1)**2 / 0.05)) return weight这个权重图会乘到光度损失上让网络更关注那些光照条件相对稳定的区域。我在实际使用中发现这个权重机制对夜间场景的提升非常明显尤其是减少了深度图在路灯附近的“飞点”现象。3.3 夜间数据增强的具体操作数据增强这块STEPS 用了三种策略局部亮度扰动随机选择图像中的若干区域对每个区域施加不同幅度的亮度缩放。模拟路灯照射下的不均匀光照。颜色温度偏移夜间场景中路灯的色温差异很大有暖黄色的钠灯也有冷白色的 LED 灯。训练时随机调整图像的整体色温。眩光模拟在图像中随机位置添加高斯光斑模拟车灯或路灯的眩光效果。这些增强操作在训练时以一定概率随机组合让网络见过足够多的光照变化模式。需要注意的是增强的强度不能太大否则会破坏图像的结构信息导致深度估计出现系统性偏差。注意数据增强只在训练时使用推理时不要加。另外增强参数需要根据你的数据集特点调整。比如 nuScenes 夜间数据本身就有很强的眩光增强强度可以适当降低。4. 完整复现流程与关键参数设置4.1 环境准备与依赖安装复现 STEPS 需要的基础环境如下# 创建虚拟环境 conda create -n steps python3.8 conda activate steps # 安装 PyTorch根据你的 CUDA 版本选择 pip install torch1.12.0 torchvision0.13.0 # 安装其他依赖 pip install numpy opencv-python pillow tensorboard pip install timm # 如果用到了 Transformer backbone数据集方面STEPS 主要在 nuScenes 和 RobotCar 上验证。nuScenes 需要申请下载RobotCar 相对容易获取。如果只是想快速验证思路可以用 KITTI 的夜间子集虽然规模小一些但足够跑通流程。4.2 网络结构搭建STEPS 的深度网络 backbone 用的是 ResNet-18和 Monodepth2 保持一致。位姿网络也是标准的 ResNet-18 加几个卷积层。核心改动在损失函数部分。class STEPSLoss(nn.Module): def __init__(self, alpha0.5, beta0.1): super().__init__() self.alpha alpha # 光度稳定性权重 self.beta beta # 平滑损失权重 self.illum_transform IlluminationInvariantTransform(3) def forward(self, target, sources, depth, pose, K): # 光照不变变换 target_stable self.illum_transform(target) sources_stable [self.illum_transform(s) for s in sources] # 计算自适应权重 weight compute_adaptive_weight(target) # 光度重建损失 photo_loss 0 for s_stable in sources_stable: # 投影和重建 warped warp_image(s_stable, depth, pose, K) diff (target_stable - warped).abs() # SSIM 损失 ssim_loss 1 - ssim(target_stable, warped) # 加权组合 photo_loss (0.85 * diff 0.15 * ssim_loss) * weight # 边缘平滑损失 smooth_loss edge_aware_smoothness(depth, target) return photo_loss.mean() self.beta * smooth_loss这里的关键参数是 alpha 和 beta。alpha 控制光照不变变换的强度beta 控制平滑损失的权重。根据我的实验alpha0.5、beta0.1 是一个比较稳的起点。如果你的数据集夜间噪声特别大可以把 beta 稍微调大一点比如 0.15让深度图更平滑。4.3 训练策略与参数计算STEPS 的训练策略和 Monodepth2 类似但有几个关键调整学习率调度初始学习率 1e-4采用余弦退火最低降到 1e-6。夜间场景的训练比白天更不稳定学习率不宜过大。Batch Size受限于显存nuScenes 上通常用 8 到 12。如果显存不够可以用梯度累积来模拟更大的 batch size。训练轮数nuScenes 夜间子集大概需要 20 到 30 个 epoch 才能收敛。我试过 15 个 epoch 就停深度图边缘还有明显的噪声。损失权重计算总损失是光度损失、平滑损失、位姿损失如果位姿也是网络预测的的加权和。STEPS 论文里给的权重是光度损失 1.0平滑损失 0.1位姿损失 0.05。这个比例我验证过基本合理。但如果你用的是双目输入而不是单目序列位姿损失可以去掉因为双目本身就能提供尺度信息。# 训练循环核心逻辑 for epoch in range(num_epochs): for batch in dataloader: target, sources, K batch depth depth_net(target) pose pose_net(target, sources) loss steps_loss(target, sources, depth, pose, K) optimizer.zero_grad() loss.backward() optimizer.step() # 每个 epoch 结束后验证 if epoch % 5 0: validate(model, val_loader)4.4 推理与后处理推理阶段STEPS 的流程和标准自监督深度估计一样输入单张图像输出深度图。但夜间场景的深度图往往有一些噪声建议做一步后处理。我常用的后处理是中值滤波加双边滤波的组合。中值滤波去掉孤立的飞点双边滤波在平滑的同时保留边缘。滤波核大小根据图像分辨率调整通常 5x5 或 7x7 就够了。def postprocess_depth(depth_map): # 中值滤波去飞点 depth_median cv2.medianBlur(depth_map, 5) # 双边滤波保边平滑 depth_filtered cv2.bilateralFilter(depth_median, 7, 0.1, 0.1) return depth_filtered提示后处理不是必须的如果你的应用对实时性要求很高可以跳过。但如果是做离线建图或者高精度测量后处理能明显提升深度图的质量。5. 常见问题与排查技巧实录5.1 训练不收敛或者损失震荡这是夜间深度估计最常见的问题。原因通常有三个学习率太大、光度损失权重太高、数据增强太激进。排查顺序建议这样先把数据增强关掉用原始图像训练几个 epoch看损失是否稳定下降。如果稳定了说明是增强的问题逐步降低增强强度。如果还是震荡把学习率降到 5e-5 试试。最后再检查光度损失的权重夜间场景下光度损失本身就不太可靠权重可以适当降低比如从 1.0 降到 0.7。5.2 深度图在路灯附近出现大面积错误这是光度一致性失效的典型表现。路灯直射区域亮度极高相邻帧之间的亮度差异巨大网络无法从光度损失中得到正确的梯度。解决方法有两个一是加强自适应权重的作用把亮度均值偏离 0.5 较远的区域的权重压得更低二是在这些区域引入额外的监督信号比如稀疏的 LiDAR 深度点。如果你的数据集有 LiDAR 数据强烈建议加上稀疏深度监督效果立竿见影。5.3 夜间深度图的尺度不一致自监督深度估计的一个固有问题是尺度不确定性。单目序列训练时深度和位姿是耦合的网络可能学到“深度大一倍、位姿小一倍”的等价解。夜间场景下这个问题更严重因为光度损失本身就不准尺度更容易漂。解决办法是引入双目训练或者使用 IMU 提供的位姿先验。如果都没有可以在损失函数里加一个尺度一致性约束让相邻帧预测的深度在重叠区域保持一致。5.4 常见问题速查表问题现象可能原因排查方法解决思路损失震荡不收敛学习率过大降低学习率到 5e-5用余弦退火最低 1e-6路灯附近深度错误光度一致性失效可视化光度损失图加强自适应权重或加 LiDAR 监督深度图整体偏暗曝光归一化问题检查图像预处理加光照归一化层边缘模糊平滑损失权重过高降低 beta 到 0.05用边缘感知平滑尺度漂移单目固有缺陷检查相邻帧深度一致性加双目或 IMU 约束训练速度慢Batch size 太小检查显存占用用梯度累积或混合精度5.5 我踩过的几个坑第一个坑是数据增强的强度。我一开始把亮度扰动设得很大结果网络学出来的深度图在正常光照下也偏暗因为网络以为所有场景都很暗。后来把扰动幅度控制在 ±30% 以内问题就解决了。第二个坑是光照不变变换的 alpha 参数。我一开始设成 0.8想着光照不变性越强越好结果纹理信息丢失太多深度图边缘糊成一团。后来降到 0.5边缘清晰度和光照鲁棒性达到了比较好的平衡。第三个坑是验证集的选择。夜间深度估计的验证集一定要包含足够多的极端光照场景否则你调出来的参数在真实场景下会翻车。我建议至少留 20% 的夜间数据做验证而且这些数据要覆盖不同的路灯类型和天气条件。6. 实际项目中的落地经验与扩展思路6.1 在自动驾驶感知栈中的位置STEPS 这类夜间深度估计方法在自动驾驶感知栈中通常扮演两个角色一是作为独立的深度感知模块为后续的障碍物检测和路径规划提供三维信息二是作为其他任务的辅助监督比如用深度图来增强夜间语义分割的边界精度。我在一个园区低速无人车项目里用过 STEPS 的思路。那个项目夜间运行需求很强但预算有限没有高线束 LiDAR。我们用 STEPS 训练了一个单目深度模型配合一个低线束 LiDAR 做稀疏监督夜间障碍物检测的召回率比纯视觉方案提升了将近 20 个百分点。6.2 扩展到其他恶劣天气场景STEPS 的核心思路——增强光度稳定性——不仅适用于夜间对雨天、雾天、雪天也有参考价值。这些场景的共同特点是光度一致性假设受到挑战。你只需要调整数据增强的策略把夜间光照模拟换成雨雾模拟光度稳定性模块基本可以复用。我试过把 STEPS 的损失函数直接用在雨天数据上不做任何修改深度估计的误差比基线方法低了 15% 左右。这说明光度稳定性增强是一个比较通用的思路。6.3 模型轻量化与部署考虑STEPS 的原始实现用的是 ResNet-18参数量大概 11M在车载嵌入式平台上跑实时推理有点吃力。如果你有部署需求可以考虑把 backbone 换成 MobileNetV3 或者 ShuffleNetV2参数量能降到 2M 到 3M推理速度提升 3 到 4 倍。但要注意轻量化之后深度估计的精度会有所下降尤其是远距离的深度。我的经验是如果只是做近距离障碍物检测10 米以内轻量化模型完全够用如果要做中远距离建图还是得用大一点的模型。6.4 一个实用的训练技巧最后分享一个我在实际项目中总结的小技巧分阶段训练。第一阶段用白天数据预训练让网络先学会基本的深度估计能力第二阶段用夜间数据微调重点优化光度稳定性模块。这样比直接混合白天夜间数据训练收敛更快最终精度也更高。原因是白天数据的光度一致性假设成立网络可以学到准确的深度和位姿。到了夜间微调阶段网络只需要调整光照相关的部分不需要从头学深度估计。我实测下来分阶段训练比混合训练在夜间验证集上的 AbsRel 误差低了大概 8%。这个技巧在 STEPS 论文里没有提但我在多个项目里验证过效果稳定。如果你手头的夜间数据量不够大分阶段训练尤其值得一试。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑