基于恶劣雨雾天气下多传感器感知性能对比实验
本文介绍一个基于 CARLA 0.9.15 与 OpenCV 的车载相机感知性能评测模块。模块以地面载具(ego 车辆)为感知平台,在车顶挂载 sensor.camera.rgb 相机(800×600,FOV 90°),通过 CARLA 天气 API 在同一场景、同一参考位姿下依次切换 ClearNoon(清晰)、SoftRainNoon(小雨)、HardRainNoon(大雨)、HeavyFog(浓雾)四档天气,对每档采集的图像计算亮度(灰度均值)、对比度(灰度标准差)、边缘密度(Canny 边缘像素占比)三个指标(每档连续取 5 帧平均),量化雨雾天气对车载视觉感知的退化程度;测量结束后车辆切换为自动驾驶,并录制恶劣天气下的行驶演示动图。
本文档为系列实验教程:第一部分(第 1~6 节)为相机感知性能对比基准实验,量化四档天气的退化程度;第二部分(第 7 节)为图像增强恢复实验,验证经典增强算法能挽回多少感知能力。当前两部分以相机(sensor.camera.rgb)为感知对象,后续部分将扩展激光雷达等其他传感器,逐步覆盖多传感器感知对比。
1. 运行环境
| 项目 | 版本 / 说明 |
|---|---|
| 操作系统 | Windows 10 |
| 模拟器 | CARLA 0.9.15(官方预编译版) |
| Python | 3.10(carla==0.9.15 官方 wheel 仅支持 3.7~3.10,3.12 及以上无法安装) |
| 依赖 | carla==0.9.15、numpy、opencv-python、matplotlib、Pillow |
1.1 下载并启动 CARLA
- 打开 CARLA 0.9.15 官方发布页:https://github.com/carla-simulator/carla/releases/tag/0.9.15
- 下载 Windows 预编译包
CARLA_0.9.15.zip。 - 将压缩包解压到任意目录,注意解压路径中不要包含中文或空格,否则部分资源加载会出错。
- 双击解压目录下的
CarlaUE4.exe启动模拟器。首次启动需要编译着色器,等待时间较长;出现城市三维画面即表示服务端已就绪(RPC 服务默认监听本机2000端口)。
1.2 安装 Python 3.10 与依赖
- 从 Python 官网下载并安装 Python 3.10.x(以3.10.11为示例):https://www.python.org/downloads/release/python-31011/,安装时勾选 Add Python to PATH。
- 打开终端,创建并激活 3.10 虚拟环境(与系统中其他 Python 版本隔离):
py -3.10 -m venv carla_env
carla_env\Scripts\activate
- 安装依赖:
pip install carla==0.9.15 numpy opencv-python matplotlib Pillow
1.3 验证环境连通
保持 CARLA 窗口运行,在已激活虚拟环境的终端中执行:
python -c "import carla; c=carla.Client('localhost',2000); c.set_timeout(10.0); print('CARLA version:', c.get_server_version())"
输出 CARLA version: 0.9.15 即表示 Python 客户端与模拟器连接成功。若报版本不匹配错误,请确认客户端 wheel 与模拟器均为 0.9.15。
2. 实验原理
2.1 天气参数
CARLA 通过 world.set_weather(carla.WeatherParameters(...)) 控制环境天气。
本实验选取四档代表性天气:
| 天气档 | 说明 |
|---|---|
ClearNoon |
晴朗正午(基准) |
SoftRainNoon |
小雨 |
HardRainNoon |
大雨 |
HeavyFog |
浓雾(晴朗基础上设 fog_density=80、fog_falloff=0.1) |
2.2 感知质量指标
对相机图像(转灰度后)计算三个指标:
- 平均亮度 Brightness:像素均值,反映整体明暗。浓雾会使画面「白化」,亮度反而升高。
- 对比度 Contrast:像素标准差,反映层次。雨雾降低对比度。
- 边缘密度 Edge Density:Canny 边缘像素占总像素比例,反映可提取的结构信息量。雾越浓边缘越少。
3. 代码结构
完整源码位于:src/ground/weather_perception_benchmark/main.py
脚本为单文件入口 main.py,按执行顺序分为以下几个部分:
| 代码段 | 作用 |
|---|---|
| 连接 CARLA | carla.Client('localhost', 2000) 连接服务端并获取 world |
| 生成载具与相机 | 生成 ego 车辆(Tesla Model 3),在车顶(x=1.5, z=2.4)挂载 800×600、FOV 90° 的 RGB 相机;测量阶段保持刹停 |
| 图像回调 | 相机回调中把 CARLA 的 BGRA 原始数据转为 OpenCV 使用的 BGR 数组 |
| 定义四档天气 | 用 WeatherParameters 构造函数生成独立的天气对象(不能直接修改 ClearNoon 预设,否则会污染共享常量) |
| 逐档采集 | 每档测量前把车辆复位到同一参考位姿 → 切天气 → 等待 3 秒 → 连续取 5 帧计算指标均值并保存样本图 |
| 结果输出 | 写 metrics.csv、绘制三指标柱状图 weather_benchmark_metrics.png |
| 行驶演示 | 测量结束后开启自动驾驶行驶 10 秒,后台线程采帧并合成为 weather_benchmark_demo.gif |
| 资源清理 | 停止并销毁相机、销毁车辆 |
下面只解释三处关键实现,完整代码请直接查看 src/ 下的源码。
(1)相机回调:BGRA → BGR
CARLA 相机回调给出的是 BGRA 四通道字节流,需重塑数组后丢弃 Alpha 通道:
def on_image(image):
arr = np.frombuffer(image.raw_data, dtype=np.uint8)
arr = np.reshape(arr, (image.height, image.width, 4)) # BGRA
image_store['img'] = arr[:, :, :3] # BGR
(2)逐档复位 + 同场景多帧采集
每档天气前调用 set_transform 把车辆复位到出生点,保证四档天气拍的是同一场景;每档取 5 帧平均,抑制雨滴闪烁造成的单帧波动:
vehicle.set_transform(spawn_point)
world.set_weather(wp)
time.sleep(3)
# 随后连续取 5 帧,分别计算指标后取平均
(3)三个指标的计算
图像转灰度后,均值即亮度、标准差即对比度,Canny 边缘像素占比即边缘密度:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
brightness = np.mean(gray)
contrast = np.std(gray)
edge_density = np.sum(cv2.Canny(gray, 50, 150) > 0) / gray.size * 100
4. 运行步骤
-
启动 CARLA 服务端:进入 CARLA 解压目录,双击
CarlaUE4.exe,等待城市画面出现。 -
在已激活的 Python 3.10 虚拟环境中,进入源码目录运行入口脚本:
cd src/ground/weather_perception_benchmark
python main.py
- 脚本生成 ego 车辆并挂载车顶相机,测量阶段车辆固定在参考位姿(刹停),
每档天气切换前后都把车辆复位到同一位姿,拍摄同一场景,连续采集 5 帧取平均;
测量结束后车辆自动切换为自动驾驶,录制 10 秒「恶劣天气下行驶」画面并自动合成演示动图。
运行结束后在
results/目录得到: weather_benchmark_clear_noon.png/weather_benchmark_soft_rain.png/weather_benchmark_hard_rain.png/weather_benchmark_heavy_fog.png:各天气样本截图metrics.csv:指标数据表weather_benchmark_metrics.png:三指标对比柱状图weather_benchmark_demo.gif:恶劣天气下行驶的演示动图
5. 实验结果
实验设计说明:四档天气均在同一参考位姿下拍摄同一场景(下图可见四张画面的路口、红绿灯、 地面黄色网格线位置完全一致),因此图中差异只来自天气本身, 排除了「车辆位置变化导致画面内容不同」的干扰。
四档天气样本图:
| ClearNoon | SoftRainNoon | HardRainNoon | HeavyFog |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
指标对比表(CARLA 0.9.15,Town10HD,同一路口同一机位,各档取 5 帧平均):
| 天气 | 亮度 | 对比度 | 边缘密度(%) |
|---|---|---|---|
| ClearNoon | 113.6 | 43.8 | 13.93 |
| SoftRainNoon | 114.2 | 35.0 | 10.96 |
| HardRainNoon | 102.9 | 32.1 | 3.79 |
| HeavyFog | 131.0 | 35.9 | 2.21 |
从表中可以看到: - 边缘密度单调下降:13.93% → 10.96% → 3.79% → 2.21%,浓雾下可提取结构信息仅剩晴朗时的约 1/6; - 亮度:大雨明显压暗画面(102.9),浓雾则使画面白化、亮度升高(131.0); - 对比度:雨天与雾天均低于晴朗基准(43.8),视觉层次被压缩。
对比柱状图:

地面载具在恶劣天气下行驶的演示动图(浓雾中自动驾驶):

6. 结论
在同一场景、同一视角下对比四档天气,可以看到:
- 浓雾对视觉感知的退化最直接:可提取的边缘结构大幅减少(边缘密度由 13.93% 降至 2.21%,降幅约 84%), 远处建筑在画面中几乎完全消失,仅剩近处的地面标线;
- 大雨明显压暗画面(亮度 113.6 → 102.9)并缩小亮度动态范围,对比度下降,视觉层次变差;
- 小雨影响最小,但对比度仍从 43.8 降到 35.0,说明雨天对视觉感知已有可测的削弱。
同时需要注意:雨滴本身会在图像中产生伪边缘,因此雨天的边缘密度并不必然随雨量单调下降, 说明单独依靠一个指标不足以刻画感知退化,需要亮度、对比度、边缘密度多指标联合评价。
7. 图像增强恢复实验
第一部分量化了四档天气下相机图像的退化程度,一个自然的追问是:图像增强能把退化救回来多少? 本部分在与第一部分完全相同的采集流程(同参考位姿、同相机参数、同 5 帧平均口径)之上, 对退化图像施加经典增强算法,再用相同指标衡量恢复效果。
7.1 增强方法
按天气类型选择针对性的经典算法:
| 天气 | 方法 | 说明 |
|---|---|---|
| ClearNoon | 不处理 | 晴朗基准,作为恢复率计算的分母 |
| SoftRainNoon / HardRainNoon | CLAHE | 限制对比度自适应直方图均衡(clipLimit=2.0,8×8 分块)。作用于 LAB 空间的 L 通道,只拉伸亮度分布而不扰动色彩,适合改善雨天的低对比度 |
| HeavyFog | 暗通道先验去雾 | He 等人 CVPR 2009 经典算法的简化实现(omega=0.95,t0=0.1,15×15 块,以均值滤波粗精炼透射率代替软抠图) |
暗通道先验去雾基于大气散射模型 I = J·t + A:先由暗通道(RGB 最小值再做最小值滤波)估计透射率 t,
取暗通道最亮 0.1% 像素对应的原图强度估计大气光 A,再反解无雾图像 J = (I − A) / t + A。
完整源码位于:src/ground/weather_image_enhancement/main.py,
采集部分与第一部分脚本相同,新增 clahe_enhance()、defog_dark_channel_prior() 等增强与对比图生成代码。
7.2 恢复率定义
恢复率 = (增强后指标 − 退化指标) / (晴朗基准指标 − 退化指标) × 100%
- 100% 表示恰好恢复到晴朗水平;
- 超过 100% 表示过冲(增强过度,越过晴朗基准);
- 接近 0% 表示基本没有恢复。
7.3 增强恢复结果
三档恶劣天气的增强前后对比(左:原图,右:增强后):
| SoftRainNoon(CLAHE) | HardRainNoon(CLAHE) | HeavyFog(去雾) |
|---|---|---|
![]() |
![]() |
![]() |
指标对比表(与第 5 节同一机位重新采集,晴朗基准 115.1/44.2/13.75% 与第一部分存在小幅波动, 属同场景不同帧的正常差异,退化趋势一致):
| 天气 | 处理 | 亮度 | 对比度 | 边缘密度(%) |
|---|---|---|---|---|
| ClearNoon | 原图(基准) | 115.1 | 44.2 | 13.75 |
| SoftRainNoon | 原图 | 114.8 | 34.9 | 10.85 |
| SoftRainNoon | CLAHE | 113.8 | 44.3 | 16.03 |
| HardRainNoon | 原图 | 104.0 | 32.2 | 4.22 |
| HardRainNoon | CLAHE | 108.0 | 38.7 | 10.93 |
| HeavyFog | 原图 | 131.1 | 35.8 | 2.18 |
| HeavyFog | 去雾(暗通道先验) | 57.2 | 43.5 | 3.97 |
恢复率(以 ClearNoon 原图为 100% 基准):
| 天气 | 方法 | 亮度恢复率 | 对比度恢复率 | 边缘密度恢复率 |
|---|---|---|---|---|
| SoftRainNoon | CLAHE | —* | 101.1% | 178.2% |
| HardRainNoon | CLAHE | 35.9% | 54.6% | 70.4% |
| HeavyFog | 去雾(暗通道先验) | 461.5%(过冲) | 92.3% | 15.5% |
* 小雨的亮度退化仅 0.3(114.8 vs 基准 115.1),恢复率公式分母过小,数值不稳定、无实际意义,故不列出。 这也说明恢复率只在「退化显著」时才是有效评价量。
分组柱状图:

7.4 分析与结论
- 对比度最容易恢复:CLAHE 使小雨对比度恢复 101.1%(恰好回到晴朗水平),暗通道去雾使浓雾对比度恢复 92.3%, 大雨也恢复了约一半(54.6%)。直方图类算法对「分布层面」的退化确实有效;
- 边缘结构很难凭空找回:浓雾去雾后边缘密度恢复率仅 15.5%(2.18% → 3.97%),远处建筑被雾物理遮挡, 信息已经丢失,增强算法无法重建不存在的结构;
- 增强会引入新的失真:小雨 CLAHE 后边缘密度反而冲到 16.03%(恢复率 178.2%),把雨滴和湿路面反光形成的 伪边缘一并放大——与第 6 节「雨滴产生伪边缘」的结论互相印证;浓雾去雾后亮度从 131.1 拉到 57.2 (恢复率 461.5%),明显过冲、画面偏暗,说明固定参数的去雾在浓雾档下力度过猛。
因此,恶劣天气下的可靠感知不能只依赖相机图像后处理:增强算法可作为低成本的第一层补救, 但更根本的方向是多传感器融合(如不受可见光散射影响的激光雷达)与对天气鲁棒的感知模型, 这也将是本系列后续部分的内容。






