基于 Blender + HDRI 的无人机检测合成数据集生成:从光照真实感到 YOLOv8 训练的完整管线
训练一个能在空中可靠检测无人机的 YOLOv8 模型,最大的瓶颈不是算法,而是数据。真实空对空无人机图像极难获取——你需要另一架无人机在空中拍摄,天气、光照、距离、姿态的组合几乎无穷无尽,而每张图片都需要人工标注 bounding box。
本文提出一种基于 Blender Cycles 路径追踪 + HDRI 全景天空 + 3D 无人机模型的全自动合成数据集生成管线。一条命令即可批量生产带 YOLO 格式标注的 1080p 图像——无人机模型的光照、阴影、反射完全由 HDRI 天空自然驱动,Sim-to-Real gap 远小于传统合成方法。
需要明确的是:Cycles 路径追踪是一种离线渲染技术(CPU 约 2 秒/帧,GPU 约 0.15 秒/帧),其物理精确的光照计算代价决定了它无法支持实时 3D 渲染。本方案定位于高质量训练数据的离线批量生成,而非仿真环境中的实时视觉输出。对于实时渲染需求(如 SITL 闭环仿真),需要使用 EEVEE 或 Gazebo 等光栅化渲染器作为替代,但画质会有显著下降。
一、方案选型:一次走弯路的经验
在确定最终方案之前,我们实际测试了四种渲染路线。下面的对比并非纸上谈兵,而是来自动手实验的真实结论。
1.1 简单 2D 合成(OpenCV 抠图贴图)
把无人机图片抠出来贴到天空背景上,最简单的做法。问题显而易见:
- 光照不一致:无人机上的光影方向与背景天空完全无关
- 边缘伪影:抠图边缘有明显色差和锯齿
- 无 3D 姿态变化:同一张 2D 图片只能做仿射变换,无法真实表现俯仰/滚转
1.2 UE5 / Isaac Sim
Unreal Engine 5 的 Lumen 渲染质量毫无疑问是最高的,但对本任务而言杀鸡用牛刀——空中无人机检测画面 95% 是天空,UE5 的超写实地表建筑完全用不上:
| 维度 | UE5 / Isaac Sim | Blender + HDRI |
|---|---|---|
| 部署复杂度 | 完整 UE5 工程,100GB+ | 单脚本 + 便携版 Blender |
| 场景构建 | 需 3D 艺术家制作天空盒 | 直接用 Polyhaven 免费 HDRI |
| 编程接口 | C++ 或 Python 桥接 | 原生 bpy Python API |
| 无头渲染 | 需 GPU + 显示上下文 | --background 纯 CPU 可跑 |
1.3 3D Gaussian Splatting + HDRI 合成(我们实测过)
这是我们认真探索过的路线。思路很有吸引力:将 3D 无人机模型转为高斯点云,用 gsplat 实时渲染后合成到 HDRI 背景上。
我们做了什么:
- 用
mesh2gaussian将 DJI Mavic 3 的 GLB 模型直接转换为 180 万个高斯点云 - 另外下载了 F-16、Su-57 等战斗机模型做同样的转换
- 用
gsplat渲染后与 HDRI 背景 alpha 合成 - 渲染速度达到了 50+ FPS
为什么放弃: 3DGS 的核心问题在于它是一种外观捕获方法,而非光照交互方法。无论原始模型多精细,转为高斯点云后只存储了固定的 RGB 颜色——放到新的 HDRI 环境中不会产生正确的光照响应:
| Blender Cycles + HDRI | 3DGS + HDRI 合成 | |
|---|---|---|
| 光照 | HDRI 真正照亮物体 | 物体颜色固定,HDRI 只是背景 |
| 材质 | PBR(金属度、粗糙度) | 仅 RGB 颜色,无材质 |
| 阴影 | 自然产生自阴影和 AO | 无阴影 |
| 反射 | 金属表面反射环境光 | 无反射 |
一句话总结:Cycles 是”物体在环境中”,3DGS 合成是”物体贴在环境上”。50 FPS 的速度优势在离线数据生成场景中毫无意义。
1.4 最终选择:Blender Cycles + HDRI
HDRI 全景天空本质上是一张记录了全方位真实光照信息的 360° 照片(HDR 格式,保留完整辐射度量)。Blender Cycles 的 IBL 用这张全景图同时作为:
- 背景:相机看到的天空就是 HDRI 本身
- 光源:HDRI 中的太阳、云层直接照亮 3D 模型
- 环境反射:模型表面的反光也来自 HDRI
模型的光照与背景天生一致,不需要任何灯光设置。
二、渲染管线架构
1 | ┌─────────────┐ |
整个管线从输入到输出:
- 输入:GLB 模型 + HDRI 文件夹 + 配置参数
- 处理:Blender Cycles 逐帧渲染(IBL 光照 + 域随机化 + 3D→2D bbox 投影)
- 输出:JPEG 图像 + YOLO 标注 + train/val/test 划分 +
dataset.yaml
三、环境搭建
3.1 安装 Blender(便携版,无需 sudo)
1 | cd ~ |
WSL2 用户注意:Cycles 在 WSL2 中通常无法使用 GPU(OptiX/CUDA),会自动回退到 CPU 渲染。这只影响速度(单帧约 2 秒),不影响画质。需要安装 xvfb 提供虚拟帧缓冲:
1 | sudo apt install xvfb |
3.2 准备 HDRI 天空
从 Polyhaven 下载 4K .hdr 格式天空图,或使用项目自带的下载脚本:
1 | bash download_assets.sh |
建议至少 10 张以上,涵盖晴天、多云、黄昏、日出等不同天气。
为什么必须 4K? HDRI 是 360° 全景图,映射到 1080p 画面时只使用一个约 30°-50° 的锥形视角。2K HDRI 展开后像素密度不足,背景会模糊。4K 是 1080p 输出的最低要求。
3.3 准备 3D 无人机模型
下载 .glb 或 .gltf 格式模型(保留 PBR 材质信息),放入 models/ 目录即可:
- Sketchfab(搜索 “drone”,筛选 “Downloadable”)
- TurboSquid
- 自建模型
四、核心代码解析
完整代码见 render_cycles.py,下面拆解关键模块。
4.1 HDRI 环境光照
整个方案的灵魂——用 Shader Node 把 HDRI 同时设为背景和光源:
1 | def setup_hdri(hdri_path: str, rotation_z: float = 0.0, strength: float = 1.0): |
关键参数:
rotation_z:每帧随机旋转 HDRI,等效于改变太阳方向。一张 HDRI 可以派生出无穷多种光照条件strength:随机化光照强度(0.9~1.5),模拟不同曝光
4.2 模型导入与归一化
不同来源的模型尺寸千差万别,必须统一归一化:
1 | def import_model(model_path: str, target_size: float = 3.5) -> list: |
设计要点:用 DroneRoot Empty 节点作为所有 mesh 的父节点,后续改变无人机姿态只需旋转这个 Empty,所有子 mesh 自动跟随。
4.3 交战构型建模
真实拦截场景中,相机与无人机的相对位置不是随机的——它遵循空气动力学和交战几何的约束。我们定义了 5 种典型观测构型,按概率加权采样:
1 | ENGAGEMENT_PROFILES = [ |
| 构型 | 权重 | 距离范围 | 说明 |
|---|---|---|---|
| tail_chase | 35% | 30-200m | 尾追——最常见的跟踪场景 |
| side_approach | 25% | 40-300m | 侧方接近,横向交叉 |
| head_on | 15% | 50-400m | 迎头对飞,相对速度大,目标像素小 |
| above_rear | 15% | 20-150m | 上方后侧俯瞰 |
| below_close | 10% | 20-80m | 近距仰视 |
4.4 飞行姿态约束
无人机不会在空中任意翻转。真实飞行姿态有物理约束,我们用截断高斯分布建模:
1 | # 滚转角:高斯分布 σ=3°,硬截断 ±8° |
4.5 2D Bounding Box 自动标注
渲染前通过 3D→2D 投影计算精确的 YOLO 格式标注,无需渲染分割 mask:
1 | def get_bbox_2d(objects, scene, cam_obj, img_w, img_h): |
利用 obj.bound_box(每个 Mesh 的 8 角包围盒)做投影,比遍历所有顶点快 10-100 倍。标注精度 100%,零人工成本。
五、一键生成数据集
5.1 离线批量生成
1 | $BLENDER --background --python render_cycles.py -- \ |
输出结构:
1 | output/drone_dataset/ |
5.2 训练 YOLOv8
1 | pip install ultralytics |
5.3 性能参考
| 配置 | 单帧渲染 | 1500 张总耗时 |
|---|---|---|
| RTX 4090(原生 Linux) | ~0.15s | ~4 分钟 |
| i7-12700 CPU | ~2.0s | ~50 分钟 |
| i7-12700 CPU (WSL2) | ~2.5s | ~63 分钟 |
32 SPP + OIDN 降噪在视觉上已接近无噪点,进一步提高采样数的边际收益很小。
六、实时渲染模式(EEVEE 降级方案)
关键区别:前文第 3 章所述的 Cycles 路径追踪管线是纯离线渲染——每帧需对场景进行数千条光线的蒙特卡洛采样,物理精确但计算代价高昂(CPU ~2 s/帧),不可能达到实时帧率。若需在 SITL/HITL 仿真中实时输出相机画面,必须切换到光栅化渲染器。项目附带的
render_eevee_realtime.py便是为此设计的降级方案——用 EEVEE 替代 Cycles,牺牲光照精度换取 30+ FPS 的实时性。
6.1 系统架构
1 | Gazebo/PX4 SITL → [ZMQ 6DoF Pose] → Blender 渲染 → [ZMQ Frame] → YOLOv8 推理 |
6.2 拦截轨迹仿真
内置 demo 模式模拟从 400m 外逐渐逼近到 15m 的追踪过程:
1 | class InterceptionTrajectory: |
随着距离缩短,FOV 自动缩小(模拟变焦锁定),横向抖动幅度逐渐减小(越近跟踪越稳定)。
6.3 ZMQ 帧发布
每帧通过 ZMQ PUB socket 发布,下游消费者可以是推理进程、录像工具或可视化界面:
1 | # 发布端(Blender 渲染器) |
6.4 渲染引擎降级策略
不同硬件自动选择最佳引擎:
| 环境 | 首选引擎 | 帧率 |
|---|---|---|
| 原生 Linux + GPU | EEVEE Next | 30+ FPS |
| WSL2(无 Vulkan) | Cycles-Low (4 SPP) | ~0.5 FPS |
| 无 GPU 服务器 | Workbench (Solid) | 5-10 FPS |
1 | $BLENDER --background --python render_eevee_realtime.py -- \ |
七、域随机化策略汇总
| 维度 | 随机化方式 | 范围 |
|---|---|---|
| 天空背景 | 13 张 4K HDRI 轮换 | 晴天/多云/黄昏/日出/雾天 |
| 太阳方向 | HDRI 绕 Z 轴旋转 | 0° ~ 360° |
| 光照强度 | Background Strength | 0.9 ~ 1.5 |
| 观测距离 | 按构型分布 | 15m ~ 400m |
| 观测角度 | 5 种构型加权采样 | 尾追/侧方/迎头/上方/下方 |
| 相机 FOV | 按构型分布 | 20° ~ 55° |
| 目标滚转 | 截断高斯 N(0, 3°) | ±8° |
| 目标俯仰 | 截断高斯 N(-2°, 2°) | -8° ~ +5° |
| 目标偏航 | 均匀分布 | 0° ~ 360° |
域随机化的目的是让模型见过足够多样的条件组合。13 张 HDRI × 360° 旋转 × 距离/角度/姿态变化 = 近乎无穷的独特训练样本。
八、方案对比
| Blender+HDRI (本方案) | UE5/Isaac Sim | 3DGS+HDRI 合成 | 2D 合成 | |
|---|---|---|---|---|
| 光照 | 物理精确 IBL | 最高(Lumen) | 无重光照 | 无 |
| 实时性 | ✗ 离线(~2s/帧 CPU) | ✓ 实时 | ✓ 实时(50+ FPS) | ✓ 实时 |
| 部署 | 单脚本 | 100GB+ | 中等 | 单脚本 |
| 标注 | 3D 投影,100% 准确 | 引擎内置 | 需额外工具 | 手动 |
| 场景多样性 | HDRI 数量 | 需 3D 建模 | 需多场景采集 | 背景图数量 |
| CPU 可用 | ✓ | ✗ | ✗ | ✓ |
| 适用场景 | 离线训练数据生成 | 复杂场景实时仿真 | 场景重建 | 快速原型 |
| 上手时间 | 30 分钟 | 数天-数周 | 数天 | 10 分钟 |
九、已知局限与改进方向
当前局限
- 非实时渲染:Cycles 路径追踪本质上是离线渲染技术。即便在 RTX 4090 上,单帧仍需约 0.15 秒(~7 FPS),远达不到仿真闭环所需的 30+ FPS。本方案只适用于训练数据的离线批量生成,不能作为 SITL/HITL 仿真的实时视觉源。如需实时渲染,可使用项目中附带的 EEVEE 实时渲染器(
render_eevee_realtime.py),但画质会显著下降——这是渲染质量与速度之间不可避免的权衡 - 单目标:仅支持一个无人机实例,不支持多目标同框
- 无运动模糊:静态渲染,缺乏高速运动的模糊效果
- 无大气散射:远距离目标应有雾霾衰减效果
- WSL2 GPU:Cycles 在 WSL2 下无法使用 GPU 加速
改进方向
- 多目标场景:在 Blender 场景中同时放置多个不同型号的无人机
- 大气效果:通过 Volume Scatter 节点模拟大气散射
- 运动模糊:启用 Cycles Motion Blur,给无人机添加关键帧动画
- 实例分割:利用 Cycles Object Index pass 生成分割 mask
- Gazebo/PX4 对接:实现
server模式,通过 ZMQ 接收动力学引擎的实时位姿
十、项目文件结构
1 | hdri-drone-render/ |
项目地址:github.com/goodisok/hdri-drone-render
参考资料
- Polyhaven HDRI 库 — 免费 CC0 协议高质量 HDRI
- Blender Python API (bpy) — Blender 官方 Python 接口
- Sim2Air: Synthetic aerial dataset for UAV monitoring (IEEE RA-L 2022) — Blender+HDRI 生成空中无人机检测数据集的先驱工作
- BlenderProc — DLR 开源的 Blender 合成数据框架
- YOLOv8 Documentation — Ultralytics YOLOv8 官方文档
- Image-Based Lighting — IBL 技术原理
- 3D Gaussian Splatting — 3DGS 原始论文