1. 从“雾天数据集凑不齐”说起:为什么要做图像加雾增强
做工业视觉、自动驾驶感知、遥感识别或者户外监控项目的朋友,十有八九都遇到过同一个尴尬:晴天、白天、光线充足的数据攒了一堆,可一到雨雾天气,模型表现就断崖式下跌。原因不用多说——训练的时候压根没见过雾图,推理时突然来一张带雾的输入,特征分布整个乱掉。
有两条路摆在面前:一是去真实场景采集雾天数据,二是自己去“造”雾。真实采集的成本有多高不用细说,雾天可遇不可求,要凑齐不同浓度、不同光照、不同景深分布的数据,没有几个月打底根本做不完。就算等到了雾天,采集设备和标注人力又是一笔开销。相比之下,对现有图像做加雾化处理,人为扩充带雾样本,是性价比高得多的一条路。
我当时做某户外检测项目时就是这么干的。项目里拿来训练的图像大部分来自晴好天气下的历史数据,但交付现场经常是清晨、雨后、近水区域,动不动就是轻雾或浓雾。一开始直接从真实场景重新采集,试了两周发现进度根本走不动。后来改成对训练集做加雾增强,模型准确率提了十几个百分点,整个项目周期也压缩下来了。
这篇文章就把我在这个方向上的完整思路、常用方案、具体写法和踩过的坑都整理一遍。如果你正要扩充带雾训练集,或者做的项目经常面对低能见度场景,这篇内容能帮你少走不少弯路。
2. 先搞清楚加雾背后的物理模型:大气散射模型的由来与数学形式
2.1 雾是怎么“遮”住图像的
在做图像加雾之前,最好先把雾的本质搞清楚。雾天拍照,传感器接收到的光信号实际是两部分:一部分是目标物体反射的光穿过大气到达相机,另一部分是大气中悬浮颗粒对光源(太阳光、环境光)的散射光直接进入相机。这两部分叠加起来,就是最终成像。
所以雾图并不是简单地“原图变白了”“对比度降低了”,它还有一个很隐蔽的影响:景深越远的目标,被衰减得越厉害,同时叠加进来的大气散射光也越多。这也是为什么近处的物体在雾天还能看清,远处的山或者楼几乎融进背景里。如果加雾时没有考虑深度信息,把所有区域均匀地“刷白”,那生成的雾图就很容易被模型“识破”,因为真实雾图的雾浓度在空间上是有梯度的。
2.2 大气散射模型的数学表达
计算机图形学和计算机视觉领域里,最常用的大气散射模型可以写成下面这个形式:
I(x) = J(x) * t(x) + A * (1 - t(x))其中:
I(x)是观测到的带雾图像(即最终合成结果);J(x)是无雾清晰图像(即原始干净图像);A是全局大气光值,可以理解为无限远处大气散射光的强度;t(x)是透射率图,取值范围在 0 到 1 之间,表示物体反射光经过大气衰减后到达相机的比例。
透射率t(x)通常建模为随距离指数衰减:
t(x) = exp(-β * d(x))其中β是大气散射系数,控制雾的浓度,β越大雾越浓;d(x)是场景深度,表示每个像素对应的物体离相机的距离。
把两个公式合起来,就得到了完整的合成模型:
I(x) = J(x) * exp(-β * d(x)) + A * (1 - exp(-β * d(x)))也就是说,只要有一张清晰的输入图J,一份对应场景的深度图d,再设定好大气光A和散射系数β,就能通过逐像素计算合成出一张带有物理意义的雾图。
2.3 为什么这个模型适合训练数据增强
这个模型之所以在工程中被广泛使用,因为它解决了一个非常实际的问题:雾的浓度和分布是由场景深度决定的。真实雾天里,远近物体的清晰度是不同的,这给模型提供了非常强的监督信号。如果模型在训练时见过大量“深度相关”的雾图,它学到的特征就不只是“图像对比度低”这么简单,而是隐含了“远处的物体本来就不该太清楚”这种先验。
我之前做过一个小实验:用同一批清晰图,分别用“均匀高斯雾化”和“模型化加雾”扩充训练集来训练同一套检测模型,在真实雾天测试集上,后者的准确率明显更高。原因是均匀高斯雾化只是降低了图像对比度,没有改变远近物体的相对清晰度关系,模型学到的东西和真实雾天的成像规律不匹配。
2.4 深度图从哪来
问题来了:上面的模型需要深度图d(x),但一般的训练图像是普通彩色照片,没有深度信息。解决这个问题有几条路:
- 使用双目或深度相机采集的数据:某些数据集本身自带深度图,比如自动驾驶领域的公开数据集,直接拿深度通道来用。
- 单目深度估计模型:用训练好的单目深度估计网络(后文会细说)给普通图像估出一张深度图。这是我用下来最顺手的方案。
- 简化场景假设:如果图像内容比较简单,比如纯路面、天空占比较高的场景,可以直接构造一张“近处亮、远处暗”的近似深度图,也能达到够用的效果。
3. 工程上更实用的加雾方案:从纯颜色变换到模型化合成
3.1 方案一:基于深度估计结果的模型化合成
这是目前质量最高也最接近真实雾天效果的方式,整体流程分三步:先用深度估计网络给清晰图生成深度图,再使用大气散射模型逐像素合成,最后做颜色空间微调。
平时我用得最多的深度估计网络是 MiDaS,这个模型对纯静态图像就能输出不错的相对深度,不需要额外训练。拿到深度图后,先做归一化,把深度值压到0到1区间,然后代入上面那个公式就行。
深度图归一化之后,透射率图的取值范围会直接影响雾的视觉效果。t越接近0的地方雾越浓,t越接近1的地方越接近原图。如果是轻雾场景,β可以取值0.1~0.5;如果是浓雾,β可以拉到1.0~2.0。这个参数的设置没什么绝对标准,最好根据自己数据中物体远近的分布来做调整。
3.2 方案二:不依赖深度图的快速近似雾化
有的项目里没有合适的深度估计模型,或者图像内容比较单一(比如很多工业质检图像都是固定机位、固定背景),这时候也可以走近似路线:
最简单的做法是构建一张“中心比边缘清晰”的距离权重图。假设图像中心的物体通常离相机更近,四周更远,那么深度图就可以粗略地表示为一个二维线性渐变或者径向渐变。虽然不完全准确,但对于某些固定场景已经够用了。
还有一种做法是直接对亮度层做高斯模糊和叠加。把图像从 RGB 转到 HSV 或者 LAB 空间,提高V通道或L通道的整体亮度,再叠加不同尺度的高斯模糊,也会产生类似雾的视觉效果。不过这个方法合成的图,远处和近处的雾浓度差距不明显,视觉上“假”一点,但胜在实现简单、速度极快。
3.3 方案三:基于对抗生成网络的雾图风格迁移
再进阶一些的方案,是用风格迁移或者对抗生成网络,把真实雾天图像的特征“迁移”到清晰图像上。这种方案的优势在于不依赖物理模型,生成的雾在整个图像上的纹理细节更自然。缺点也很明显:需要大量真实雾图和清晰图的配对数据,或者至少需要足够的真实雾图来做对抗训练,这个数据本身的成本就把前面积累的优势抵消了。
在工程量产项目中,我通常不会把它作为首选。如果手头已经有大量真实雾天图像资源,倒是可以拿来和模型化合成的结果做混合训练,效果会更好。
3.4 方案对比:怎么选
用表格把这些路线做一个直观对比,方便不同项目背景的人快速决策:
| 方案 | 是否需要深度图 | 合成效果 | 实现成本 | 适用场景 |
|---|---|---|---|---|
| 模型化合成(深度图驱动) | 需要 | 接近真实雾图,有空间浓度梯度 | 中 | 自动驾驶、遥感、室外监控 |
| 近似雾化(渐变权重) | 不需要 | 可用,但细节不够自然 | 低 | 固定机位、室内、简单背景 |
| 对抗生成风格迁移 | 不需要 | 纹理自然 | 高 | 已有大量真实雾图资源时 |
| 纯色阶变换/模糊 | 不需要 | 快速但“假” | 极低 | 轻量实验、快速验证 |
我自己的经验法则是:能拿到深度图就优先用模型化合成;拿不到深度图但场景固定,就用近似雾化;项目周期特别紧、只为了快速看看模型会不会崩,那就先随便糊一层色阶变换将就一下,回头再补高质量的。
4. 动手实现:一套完整可复现的加雾增强处理流程
4.1 整体流程设计
从工程落地角度,建议把加雾增强做成一个独立模块,不要和训练代码搅在一起。理由很朴素:训练时你随时可能调整雾浓度、雾的形态、数据比例,把这些参数收敛到一个独立模块,改起来不用动主流程。
我自己在项目里习惯上的一个做法是离线矿图:先把原始清晰图跑一遍脚本生成一批雾图文件,存成和原图同目录结构的新目录,然后训练时直接把这两个目录分别喂给数据加载器,按比例采样做 on-the-fly 的随机选择。这里不建议每轮训练都现场生成雾图,因为深度估计这一步本身就挺耗时,放在训练循环里会拖慢整个速度。离线扩充一遍,后面训练效率高很多。
4.2 关键依赖与版本
代码用了 Python 3 环境,主要依赖这几个库:
torch和torchvision:用来跑深度估计模型PIL或opencv-python:图像读写和基础处理numpy:数组运算
不需要特别新的版本,我用的是常规稳定版本组合,只要保证 torch 和 torchvision 能加载模型权重就行。深度估计模型我用的 MiDaS 官方权重,模型本身对输入尺寸不敏感,处理不同分辨率的图很方便。
4.3 核心代码实现:模型化雾图合成
下面的代码就是主流程的实际实现,我在项目里跑过的版本基础上精简出来的:
import cv2 import numpy as np import torch from PIL import Image def load_depth_model(): """加载单目深度估计模型(这里以 MiDaS 为例)""" model_type = "DPT_Hybrid" midas = torch.hub.load("intel-isl/MiDaS", model_type) transform = torch.hub.load("intel-isl/MiDaS", "transforms").dpt_transform device = torch.device("cuda" if torch.cuda.is_available() else "cpu") midas.to(device).eval() return midas, transform, device def get_depth_map(image, model, transform, device): """从单张彩色图像估计深度图""" img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) input_batch = transform(img_rgb).to(device) with torch.no_grad(): depth = model(input_batch) depth = torch.nn.functional.interpolate( depth.unsqueeze(1), size=img_rgb.shape[:2], mode="bicubic", align_corners=False, ).squeeze() depth = depth.cpu().numpy() depth = (depth - depth.min()) / (depth.max() - depth.min()) return depth def synthesize_fog(image, depth, beta=1.0, A=0.8): """ 基于大气散射模型的雾图合成 image: BGR 图像,值范围 0~255 depth: 归一化后的深度图,值范围 0~1 beta: 散射系数,越大雾越浓 A: 大气光强度,0~1,通常取 0.7~1.0 """ img = image.astype(np.float32) / 255.0 depth = depth.astype(np.float32) t = np.exp(-beta * depth) t = t[..., np.newaxis] # 扩展为单通道 fogged = img * t + A * (1.0 - t) fogged = np.clip(fogged * 255.0, 0, 255).astype(np.uint8) return fogged def augment_with_fog(src_dir, dst_dir, beta_range=(0.3, 1.5), A_range=(0.7, 1.0)): """对目录下所有图像批量生成雾图""" import os os.makedirs(dst_dir, exist_ok=True) model, transform, device = load_depth_model() for name in os.listdir(src_dir): if not name.lower().endswith((".jpg", ".png", ".jpeg")): continue path = os.path.join(src_dir, name) image = cv2.imread(path) if image is None: continue depth = get_depth_map(image, model, transform, device) beta = np.random.uniform(*beta_range) A = np.random.uniform(*A_range) fogged = synthesize_fog(image, depth, beta=beta, A=A) cv2.imwrite(os.path.join(dst_dir, name), fogged) print(f"processed: {name} | beta={beta:.2f} | A={A:.2f}")这个脚本干的事情很直白:读取一张图,估计深度,随机选择beta和A,合成带雾图,写进目标目录。beta_range和A_range可以按实际需求调,如果希望生成多样化程度更高,可以把beta_range拉开一些。
4.4 参数解读:beta和A到底该怎么调
这两个参数是雾效果最直接的控制旋钮,分别控制“雾的浓度”和“整体亮度基底”。
beta是散射系数,直接决定透射率t的衰减速度。同一个深度图上,beta=0.3的时候远处的物体还能看出来轮廓,beta拉到 1.5 时远处的部分基本要和背景融为一体了。做数据增强的时候,不建议把beta固定成一个值,最好在一定范围内随机采样,这样模型能看到不同浓度的雾,泛化性更好。
A是大气光强度,决定雾的底色偏亮还是偏暗。真实雾天的底色通常不是纯白,有时偏灰蓝,有时偏灰黄。“雾”在视觉上的色调差异大体来自这个值。如果想让数据多样一点,可以把A的 RGB 分量拆开分别设定,比如A = (0.8, 0.82, 0.85),这样每个通道有一点微小的偏移,合成出来的雾色更有真实感。
from 一段实际项目的调试经验来看,beta范围设在0.3~1.5是比较舒服的区间,A值设在0.7~1.0之间比较合理。A小于 0.7 时,合成图的整体亮度和“雾感”都会显得有点脏;A大于 1.0 会直接超出像素值范围,导致高光区域被截断,丢失细节。
4.5 提升多样性的几个“变种”操作
固定模型合成虽然好,但一直用同一个规则也有问题:生成的雾图在纹理细节上可能会呈现出某种“风格统一性”,这会让模型记住合成模式而不是学会泛化。为了打破这种统一性,可以在基本流程上增加几种变形:
一是给透射率图增加空间噪声。正常生成出来的t是相对平滑的,真实雾天的透射率图多少会有一些由于空气湍流导致的局部波动。做法很简单,在t上叠加一层高斯噪声,然后做一次模糊:
noise = np.random.normal(0, 0.03, depth.shape) t_noisy = t + noise t_noisy = cv2.GaussianBlur(t_noisy.astype(np.float32), (15, 15), 0) t_noisy = np.clip(t_noisy, 0.05, 1.0)这样生成的雾在边缘和局部区域会有轻微的浓淡变化,看起来更真实。注意噪声的振幅不能太大,太大会让画面出现斑点状的“脏感”。
二是给A值加色调偏移。真实雾天的色调受环境光影响很大,早上的雾偏暖黄,样子偏冷白。可以在A的三个通道上分别乘以不同的系数,形成色调上的偏置。这样生成的雾图不再是千篇一律的灰白,而是有冷暖变化的。
三是生成多档雾浓度版本。如果一个目标需要模型在不同雾浓度下都能识别,就不要只生成一张雾图,可以给同一张原图生成beta=0.3、beta=0.8、beta=1.5三张不同浓度的图,三张都放进训练集。这样训练时的采样流程,按照“原图/轻雾/中雾/浓雾”的分布,模型对浓度变化的鲁棒性会有明显提升。
4.6 工程建议:先跑通小规模,再全量扩展
第一次使用这套流程时,最好先拿一个小文件夹做实验,比如拿 20~30 张不同场景的图跑一遍脚本,打开输出图检查一下视觉效果。重点检查几个地方:远处物体是不是被雾盖住了而近处还保留清晰度?天空区域是不是还能看出层次?有没有出现原图高光区域被 A 值拉爆导致的一片死白?
如果效果没问题,再对全量数据集扩展。批量跑的时候建议开 GPU,深度估计模型在 GPU 上跑和 CPU 上跑的速度差个 10 倍以上。CPU 也能跑,就是慢,一个上千张的标注数据集可能要跑几个小时,GPU 能在十几分钟到半小时内搞定。
5. 加雾增强的工程化实施:数据配比、目录管理与训练集成
5.1 训练集里雾图的比例怎么定
扩充训练样本不是简单地把雾图全塞进训练集就行,比例失衡会让模型产生新的偏见。如果雾图占比太高,模型在晴天场景下反而会掉点;占比太低,加雾增强又起不到明显效果。
我实际测试下来的一个经验是:以目标应用场景为准。如果实际部署环境中“雾天出现率”大概在 20%~30%,那训练集里雾图比例最好设置在 15%~30% 之间,完全复刻真实分布即可。如果实际部署很多雾天,比如某个区域野外环境,那比例可以升到 50% 甚至更多,但不要超过 70%,否则模型对清晰无雾输入的处理能力会被严重削弱。
还有一个容易忽略的细节:不要让同一个目标的所有雾图全部集中在某一个类或者某一段目标大小区间。扩充的时候注意按类别的原始分布去采样,避免某个小类别突然在雾图里被放大了权重。
5.2 目录结构和加载器的设计
如果离线生成了雾图,目录结构建议这样组织:
train/ clear/ img001.jpg img002.jpg fog/ img001.jpg img002.jpg两张名字一样的图分别代表同一张原图的清晰版和雾图版。这样在做数据加载时非常方便:按训练迭代随机选择clear或fog目录,剩下逻辑都不用改。如果同一样本存在多档雾浓度,可以在fog目录下再分子目录,或者文件名加后缀,比如img001_beta0.3.jpg。
训练时,数据加载器每取到一张图,按既定概率决定取清晰图还是雾图。如果做随机增强时想用 online 方式,把synthesize_fog函数组装到数据加载器里也是可以的,但前面说过,深度估计这一步太慢,不建议放在实时加载流程里。
5.3 验证集和测试集要不要加雾
这个问题遇到过不少同行来问。我的建议非常明确:验证集和测试集不要用合成的雾图,尽量使用真实雾天图像,哪怕数量少也要保证来源是真实的。理由是模型在训练过程中见过大量合成雾图,它在合成雾分布上的表现不一定能代表真实雾天场景下的表现。如果验证集也用同一套合成方法,就会得到一个“自嗨”的评估指标,看起来涨点了,实际落地一测又被打回原形。
如果实在搞不到真实雾图做验证,退而求其次的做法是:用另一套完全不相关的合成方法来做验证集雾图,保证合成机制有差异,这样评估结果相对可信一些。我当时项目里就是同时用了两种不同策略来做训练增广和验证集雾化,效果比用同一套方法好不少。
6. 加雾增强后模型训练效果如何评估:不看单一指标,看多维度对比
6.1 评估指标的选择
加了雾图扩充之后,怎么判断增强到底有没有用,不能只看在雾天测试集的准确率涨了没有,还需要看模型在原本清晰图上的表现有没有退化。用一张表来列一下我常用的评估维度:
| 评估维度 | 指标示例 | 期望变化 |
|---|---|---|
| 清晰测试集表现 | mAP、准确率 | 基本保持或略有下降(不超过 2%) |
| 雾天测试集表现 | mAP、准确率 | 明显提升(提升 5% 以上视为有效) |
| 雾浓度鲁棒性 | 不同 beta 下连续测试 | 随浓度增加,性能下降幅度平缓 |
| 边界框定位稳定性 | IoU、中心点偏移 | 雾天下的 IoU 下降幅度收窄 |
在实际项目里,那个“雾浓度鲁棒性”维度很值得关注。把测试集中加入不同合成浓度的雾图,依次评估,看模型性能随浓度增加的衰减曲线。如果增强有效,曲线整体会变得更加平缓。光看一个平均准确率,有时候看不出来模型是不是只在轻雾下好用、一到浓雾又崩了。
6.2 一个实际项目的效果变化参考
我之前做的那个室外检测项目,加雾增强前后有这么一组数字:在真实雾天测试集中,增强前的 mAP 大约是0.41,加雾增强训练之后涨到0.56,提升了约 15 个百分点;同一时间,清晰测试集合的 mAP 从0.78微降到了0.76,完全可以接受。项目里那几张出现频率最高的误检类目——远处目标漏检和低对比度下误检,也有明显改善。
如果把雾浓度分成轻、中、浓三档单独统计,增强前浓雾档的 mAP 只有0.25,增强后到了0.49,翻了一倍,这基本能直观说明模型对重度雾天泛化能力的变化。
6.3 搞清楚涨点到底来自“雾”还是来自“数据量”
做对比实验时有一个容易忽略的干扰因素:加雾图等于增加了训练集的总数据量,性能提升可能仅仅来自数据量的增加,而不是加雾这一操作本身的贡献。
要排除这个干扰,需要设计一个对照实验:从清晰图中随机抽取相同数量的样本,复制一份作为扩充数据加回去,和加雾扩充做对比。如果“复制清晰图”的那一组性能提升明显小于“加雾扩充”那一组,才能说明雾图增强真正有效。这类对照组实验不一定每次项目都要做,但如果要考虑发布决策,最好还是先把这个结论验证扎实。
7. 实际操作中的坑与排查实录
7.1 坑一:深度图估计错乱导致雾图出现“光晕假象”
第一次跑通模型化合成时,我遇到一个很典型的问题:某些图像里物体边缘出现了一圈明显的光晕,尤其是天空和高楼交界的地方,合成出来的雾图边缘发亮发虚,和真实雾图差得很远。
排查之后定位到问题根源:单目深度估计模型在天空和前景物体的深度边界处会生成不连续的深度突变,这个突变透射到大气散射模型里,就形成了肉眼可见的边缘伪影。解决办法是对深度图做一次导向滤波或者快速双边滤波,在保留大结构的同时平滑掉边缘附近的小噪点。实际操作时,我直接用了cv2.bilateralFilter(depth, 15, 0.2, 0.2),效果也够用。
7.2 坑二:A 值统一导致雾色发灰白,适配不了暖色场景
合成雾图的底色完全由A决定。如果所有样本都用同一个A,你会发现整批雾图的色调非常统一,尤其是这个场景本身偏暖色调时,生成的灰白雾和场景原色调格格不入。这个问题在视觉美观上还算小事,对模型来说,就是让模型在特征层面偷懒地依赖“灰色调”来识别雾天,而不是依赖真正的物理特征。
解决方式前面提过,随机化A分量并对 RGB 三个通道做独立微调。再进阶一点,可以基于场景本身的平均色调来设定A,使雾的颜色接近场景环境光的自然颜色,而不是凭空给一个固定白灰色。
7.3 坑三:浓雾样本过拟合到“过曝”区域
A值接近 1.0 的时候,很多暗部区域的像素值会被整体拉高,图像中原本明亮的部分会直接顶到 255 变成死白。模型在训练中见到太多这种过曝样本之后,遇到真实雾天有时会把正常偏亮的区域也误判成过曝,导致漏检。
这个问题的缓解手段是在合成之后做一个轻微的高光压缩,或者把A的天花板值控制在 0.92 以下,别太贪极致效果。想让雾看起来更浓,优先增大beta而不是把A顶到上限。
7.4 坑四:CPU 推理深度估计太慢,成为扩充瓶颈
这一点在前面提过一次,但值得展开:单张图像用 MiDaS 在 CPU 上估计深度,1080p 分辨率大约要 2~4 秒,1000 张图就是 40 分钟到 1 个多小时。如果项目数据量到几万张,这个时间是完全不能接受的。
替代方案有两个方向:一是给整批图像做等比例下采样后再估深度,反正深度图最后都要 resize 回原尺寸;二是只用轻量级深度估计模型,不需要那么高的精确度,速度快很多。我后来在其中一个项目上把输入图下采样到半分辨率,深度估计时间降了一半还多,合成雾图的视觉质量几乎没差。
7.5 常见问题速查表
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
| 边缘出现光晕伪影 | 深度图边界不平滑 | 对深度图做双边滤波或导向滤波 |
| 雾色太灰白,和场景不搭 | 大气光 A 固定为灰白色 | 随机化 A 并对 RGB 通道微调 |
| 高光区域死白 | A 值太大或 beta 太小 | A 控制在 0.92 以下,优先增大 beta |
| 合成雾图整体偏暗 | A 值太小或原图本身亮度低 | 适当提高 A,或对输入图做亮度归一化 |
| 批量扩充太慢 | CPU 推理深度估计 | 下采样输入图像,或换用轻量级模型 |
| 模型在清晰图上掉点明显 | 雾图比例过高 | 降低雾图占比,做对照实验确定合理比例 |
8. 再补充一个务实的小技巧:把“加雾增强”和“去雾”组合起来用
如果你已经能做到把清晰图变成雾图,那反方向的套利空间也很大:雾图加回清晰图,可以做图像去雾任务的数据集。也就是说,同一套大气散射模型、同一批深度图,既能给检测模型做增强,也能用来训练一个去雾模块。
有些项目实际的做法是:在推理时增加了一个图像预处理阶段,先用一个轻量级去雾网络把输入图“还原”一下,再喂给检测网络,效果比直接让检测网络硬抗雾天要好。这个预处理的训练数据,恰好就是上面这套流程生成的配对数据——原图是标签,合成雾图是输入。一次工程投入,两边都能用,很划算。
我之前手头有个项目就是这么做的:先离线圈生成几千张雾图对,训练了一个小型去雾网络,推理时先做一次去雾预处理,后续检测精度在真实雾天测试集上又涨了一截。这个技巧不一定适合所有场景,如果你的检测网络本身就是对雾天做过专门增强的,再加去雾模块可能反而画蛇添足。
9. 基于个人经验的三点心得式收尾
这套加雾增强流程从最初用最简单的色阶变换,到后来用深度图驱动的物理模型,再到配合训练比例和评估机制做调优,我前后用了好几轮才把效果稳定住。过程中最大的感受是:合成雾图的“物理真实性”比“视觉效果”更重要。很多人一开始只看雾图好不好看、雾浓不浓,却没意识到真正的衡量标准是合成图和真实雾图的成像规律是否一致。远近物体的清晰度差异、雾的色调环境、边缘过渡的自然度,这些才是模型能泛化的关键。
第二点心得是关于“增强力度”的克制。数据增强有一个边际效应递减的规律,加雾图的占比不是越高越好,浓度分布也不是越极端越好。模型见惯了极端浓雾,到了真实场景反而可能矫枉过正。把增强控制在和真实分布相近的范围内,往往测试指标最优。
第三点,也是我很想提醒大家的:不要被合成图上的漂亮指标冲昏头脑。训练集的雾是造出来的,验证集最好用真实的雾天数据来检验。如果连真实雾图都拿不到,至少换一种合成机制去交叉验证。否则模型到底是在泛化雾天能力还是在背合成公式,这一点都搞不清楚的话,后续上线风险是相当大的。
这些经验不一定每个场景都成立,但在这个方向上,它们确实是实打实摸出来的心得,希望对你有参考价值。