# 合成数据生成 ## 1. 如何构建传感器 Dump 数据采集 ```{admonition} 注意 :class: tip 相关文档 [ 传感器 dump 虚拟标注数据集](https://nrwsxho0n9.feishu.cn/wiki/EPVVwHC2AiDelCk1V0ncT1C3nyg) ``` ```{admonition} 注意 :class: tip **Dump** 为了满足客户通过**高精度渲染场景生成数据集**的需求,我们在传感器的数据输出方式上添加了 Dump 这一方式。选择此输出方式的情况下,我们会在用例运行过程中将对应**传感器采集的数据**以及**每一帧数据对应的真值数据**(**groundtruth**)储存在指定目录。 ``` ![](images/112_Synthetic_Data_Generation/image1.png) ### 1.1 普通用例生成 Dump 数据集介绍 除了用例测试外,SimOne 仿真平台对感知系统算法的测试与训练可以提供带标注的真值。 * **摄像头仿真**:提供语义分割图、深度图、2D/3D 包围盒等带注释的图像数据集单目、广角等摄像头的仿真。 * **激光雷达仿真**:提供点云原始数据,带标注点云数据,识别物的包围盒等数据。 * **毫米波雷达仿真**:提供目标级毫米波雷达检测物数据。 ```{admonition} 注意 :class: tip 这里以 Dump 摄像头感知信息为例,SimOne 提供两种方式 Dump 感知信息,手动 Dump 与自动 Dump。Dump 结果以 raw data 给出,解析之后样例如下: ``` ![](images/112_Synthetic_Data_Generation/image2.png) ### 1.2 录制回放时自动 Dump SimOne 仿真平台同时支持通过录制回放功能,自动 Dump,以实现不同环境条件下的时间一致性。新网页针对每次运行用例都会进行录制,可以借助此功能进行回放时的自动 Dump。 ```{admonition} 注意 :class: tip **为什么需要创建一个回放用例用于 Dump?** Dump 过程为了保证数据质量**对仿真硬件压力较大**,尤其是将大量仿真数据写入硬盘的过程,因此我们一般**鼓励每次 Dump 一个物理级传感器**的数据,而如果有主车上安装有多路传感器,需要各路传感器在时间上同步的数据时,**使用同一回放用例,就可以确保数据在时序上的一致性。** ``` 主要步骤如下: #### 1.2.1 新建一个用于回放的交通流用例 1. 选择内置 **用例库** 中 **入门用例** 中的 **构建交通流用例**,用于路径回放录制,勾选 **构建交通流案列**,点 **运行** 如下图所示,运行一遍已编辑好的用例(在主车没有添加 Camera 的情况下)。 ![](images/112_Synthetic_Data_Generation/image3.png) 2. 用例运行时选择 **手动控制** 主车即可,具体操作如下图所示。 ![](images/112_Synthetic_Data_Generation/image4.png) 3. 点击 **创建**,用例运行起来,用户可以根据自己需要在地图跑一段自己需要的路径,一段时间后结束用例运行。 ![](images/112_Synthetic_Data_Generation/image5.png) #### 1.2.2 配置用于 Dump 的车辆 1. 在主车管理模块,新增一辆主车名,可以重命名为 data。 ![](images/112_Synthetic_Data_Generation/image6.png) 2. **摄像头** 和 **激光雷达** Dump 配置:为此主车配置一个摄像头和激光雷达,设置 Dump 参数,如下图所示,图中**输出设置** **输出到 Dump**。 ![](images/112_Synthetic_Data_Generation/image7.png) 3. 然后下面会出现 **RGB**、**语义分割图**、**深度图**、**实例分割图**、以及 **真值** 多种选择,用户可以按需勾选。 ```{admonition} 注意 :class: tip Dump 帧率对于摄像头最多 30hz,Dump 时间根据客户需求可以从 **录制回放** 路径中选择自己比较满意的时间段,这里选择的是 20 秒到 25 秒。 ``` 4. Dump 路径在保存到参数设置,这里路径选择的是: *C:/Dump* ,用户根据自己需求选择保存路径,系统会自动创建文件夹。 5. 为了使摄像头与激光雷达的数据做到硬同步这里 Dump 帧率与 Dump 时间段都设置一样,激光雷达能够达到的最大 Dump 帧率为 10hz,所以为了达到多传感硬同步,用户要注意帧率的限制。 ```{admonition} 注意 :class: tip **所有配置在一台车上的传感器都需要硬同步吗?** 目前是这样处理的,因为真实传感器肯定是同步工作的且一般客户会有融合数据进行感知的需求。 ``` ```{admonition} 注意 :class: tip 虽然摄像头和激光雷达帧率相同,但它们的仿真过程是**交给不同的渲染节点**去实现的,同时 Dump 不仅**对仿真硬件压力较大**,还会因**写硬盘的速率瓶颈导致效率的严重下降**,甚至部分数据丢失,因为我们建议一次只 Dump 一路传感器的数据。 ``` 6. **激光雷达**参数设置如下图所示: ```{admonition} 注意 :class: tip 这**两个传感器不能同时 Dump**,**为了效率提升**,在 Dump 图像时需要**把激光雷达关掉**,将激光雷达界面右上的启用按钮点击下即可,同理摄像头关掉也需要点击这个启用按钮。 配置好传感器 Dump 参数,就可以进行 Dump 了。 ``` ![](images/112_Synthetic_Data_Generation/image8.png) 7. 如配置 **毫米波雷达** Dump:为此主车配置一个毫米波雷达,设置 Dump 参数,如下图所示,图中圈红的地方在输出的地方选择 Dump 参数。 ![](images/112_Synthetic_Data_Generation/image9.png) 8. 然后下面会出现帧率配置,Dump 时间,Dump 保存路径的配置,按照你的需求配置好后,就可以启动仿真了。 ![](images/112_Synthetic_Data_Generation/image10.png) ```{admonition} 注意 :class: tip 输出到 Dump, **DumpHz**:自动 Dump 图像的频率 **DumpStartTime**:自动 Dump 图像的开始时间(秒) **DumpEndTime**:自动 Dump 图像的结束时间(秒) **DumpOutputPath**:配置 Dump 后图像的存储目录。 此目录必须存在。 ``` #### 1.2.3 保存为回放用例 点击用例已完成切到 **已完成** 界面,点击右侧的 **保存** 按钮,将回放重新保存到用例库(用例标识为紫色)。 ![](images/112_Synthetic_Data_Generation/image11.png) ![](images/112_Synthetic_Data_Generation/image12.png) #### 1.2.4 运行回放用例 图中紫色字样的为刚才创建的录制回放用例,运行用例选择我们配置有摄像头以及激光雷达的主车 data,即开始 Dump 图像或者点云数据(data 上的摄像头与激光雷达不能同时开)。 ![](images/112_Synthetic_Data_Generation/image13.png) ![](images/112_Synthetic_Data_Generation/image14.png) #### 1.2.5 查看 Dump 结果 Dump 的图像与点云数据目录默认为 C:/Dump 如图所示。 ![](images/112_Synthetic_Data_Generation/image15.png) ![](images/112_Synthetic_Data_Generation/image16.png) ![](images/112_Synthetic_Data_Generation/image17.png) ![](images/112_Synthetic_Data_Generation/image18.png) ### 1.3 Dump 数据转化 #### 1.3.1 摄像头传感器 dump 数据转化 ##### 1.3.1.1 环境准备 1. 安装 python,配置相应的环境变量。 2. 安装第三方库 opencv。 ```python pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python==4.5.5.62 ``` ##### 1.3.1.2 执行 python 脚本 ###### 1.3.1.2.1 方法一 1. 拷贝安装路径 安装路径*/SimOne/Tools/RAW2PNG.py* 文件到目录 *C:/Dump *的传感器目录下 ![](images/112_Synthetic_Data_Generation/image19.png) ![](images/112_Synthetic_Data_Generation/image20.png) 2. 运行 py 文件`py RAW2PNG.py` 后,会生成一个 out 文件夹,Dump 的图像数据目录如图所示。 ![](images/112_Synthetic_Data_Generation/image21.png) ![](images/112_Synthetic_Data_Generation/image22.png) ![](images/112_Synthetic_Data_Generation/image23.png) ![](images/112_Synthetic_Data_Generation/image24.png) ###### 1.3.1.2.2 方法二 1. 打开 */SimOne/Tools/RAW2PNG.py* 文件脚本。 ![](images/112_Synthetic_Data_Generation/image25.png) 2. **执行命令** ```python python /SimOne/Tools/RAW2PNG.py --input="D:/Dump/Dump/1-1/cam_front" --output="D:/Dump/Dump/1-1/cam_front/output" ``` ```{admonition} 注意 :class: tip python /SimOne/Tools/RAW2PNG.py // python 脚本路径 \--input="D:/Dump/Dump/1-1/cam\_front" // 需要转化 dump 数据的存储路径 \--output="D:/Dump/Dump/1-1/cam\_front/output" // 转化后数据的存放路径 ``` **示例:** **--input 示例** 各传感器 dump 所在文件夹 ![](images/112_Synthetic_Data_Generation/image26.png) **--output 示例** * Color 摄像头拍到的真实数据 * Colorbox 3Dbox * ColorOpenLane 车道线分割图 * DepthPlanner 深度图 * Instance 实例分割图 * Segmentation 灰度图 * SegmentationView 语义分割图 ![](images/112_Synthetic_Data_Generation/image27.png) ![](images/112_Synthetic_Data_Generation/image28.png) #### 1.3.2 激光雷达传感器转化点云 ##### 1.3.2.1 环境准备 安装转化 pcd 格式的点云程序,如 CloudCompare,也可自行下载其他转化程序。 ##### 1.3.2.2 pcd 转化点云 打开 CloudCompare 程序,将 pcd 文件拖入此程序中,程序中显示点云。 ![](images/112_Synthetic_Data_Generation/image29.png) #### 1.3.3 BEV 拼接工具使用 ##### 1.3.3.1 功能背景 BEV 技术通过传感器数据提供**鸟瞰视图**,用于自动驾驶等领域,提高环境感知能力。BEV 感知技术具有**遮挡处理**、**全局视野**、**并行执行多任务**等特点。其工作原理包括**数据获取**、**预处理**和 **BEV 视角转换**。BEV 图像在自动驾驶领域应用广泛,**如环境感知、物体检测、路径规划等**。 在利用 BEV 视角图像来进行做进一步应用前,需要进行**数据标注**。在对真实数据的标注中,往往有被遮挡,光照阴影等原因导致的精确度不足问题,数据类型上有场景多样性的不足,同时还有时间成本巨大的缺陷。 本工具结合 SimOne 进行 BEV 数据生成和拼接,通过示例算法获得 BEV 图像,并标注出**停车位真值信息**,会包含在安装包中,暴露给客户,路径为 **SimOne/Tools/BEVTools/**。 ##### 1.3.3.2 数据生成 本工具需要配合 SimOne 使用,通过使用 SimOne 输出仿真数据。 在主车中添加**鱼眼摄像头**,配置不足时可分为四个主车,每个主车配置一个方向的鱼眼相机,然后通过回放案例的方式来生成同一条测试线路的各向鱼眼相机数据。 ###### 1.3.3.2.1 鱼眼相机设置 在添加多路鱼眼相机后需要对其进行设置,除成像设置按需更改外,需要对输出设置进行更改: 1. 点击 **输出到** 一栏的选择框,在下拉菜单中选择 **Dump** 。 2. 在新出现的菜单中,勾选 **RGB**、**深度图**、**车道线**。 3. 按照仿真机器的配置高低选择 **Dump** **频率。** 4. **Dump** **开始** 和 **Dump** **结束** 分别对应在仿真运行时 Dump 数据的开始时间和结束时间,由于在启动运行案例可能有一定的等待时间,建议开始时间可以选择 **10s** 时间,以免 dump 数据中出现过多的车辆停止状态的冗余数据。 5. 在 **保存到** 一栏填入**输出数据的目标路径**,dump 数据会在运行案例后,于对应路径下新建文件夹,并存入其中。 6. 重复上述过程,对各方向的鱼眼相机均进行正确配置。 ![](images/112_Synthetic_Data_Generation/image30.png) ###### 1.3.3.2.2 Dump 数据建议流程 由于仿真机器的配置高低差异,这里提供一种较为普适可行的 Dump 数据流程。 1. 准备好5辆主车,其中一辆主车不添加鱼眼相机,其余各添加一个方向的鱼眼相机,并配置 Dump 相关。 2. 使用无鱼眼相机主车进行案例仿真(**案例名不要带中文**),将需要的路线跑出来之后停止案例,在 **任务管理** ->**已完成** 一栏中找到完成的任务,点击展开按钮,点击下图所示按钮,创建数据回放按钮,在弹窗中,**转换为** 一栏选择 **回放用例** ,点击 **创建** 。 ![](images/112_Synthetic_Data_Generation/image31.png) 2. 在**用例管理**中,找到刚刚创建的回放案例,点击选择后点击 **运行** 按钮,在弹窗中 **主车类型** 一栏中选中配置了各向鱼眼相机的主车,将四个方向的数据依次输出出来。 ##### 1.3.3.3 准备数据 在四路相机输出完 dump 数据后,将文件夹整理如下图类似的结构,数字部分为 dump 路径中的子文件夹内容: ```sql DumpData ├── back │ ├── 600 │ └── ··· ├── front │ ├── 600 │ └── ··· ├── left │ ├── 600 │ └── ··· └── right ├── 600 └── ··· ``` 其中“600”等子文件夹,是各方向相机 dump 输出路径下的子文件夹。 ##### 1.3.3.4 数据拼接转换 ```{admonition} 注意 :class: tip **工具所在目录**:安装目录\SimOne\Tools\BEVTools\\ ``` 1. 打开命令行,输入如下指令,即可开始转换(可以自己建立 res 文件夹或工具会自动创建): ```sql main.exe --input E:\\DumpData\\ --output E:\\DumpData\\res ``` E:\\\DumpData\\\文件夹下需要有 front,back,right,left 四个子文件夹,分别是对应的四路鱼眼相机 dump 数据,输入路径应为绝对路径。 ```json 可选的额外参数有 --bev_only: 设置为 True 时,仅输出 BEV 图像。默认为 False。 --json_only: 设置为 True 时,仅输出 json 格式的真值数据。默认为 False。 --show_json_on_img: 设置为 True 时,将真值数据叠加在图像上并输出。默认为 False。 ``` 2. 稍作等待即可得到转换后的 BEV 图像和标注结果。 - E:\\\DumpData\\\文件夹下的 front,back,right,left 四个子文件夹中会有”out”文件夹,是将 dump 数据转换为 png 图像结果 - E:\\\DumpData\\\res 中会有 bev\_image,json,json\_image 三个文件夹结果,分别存放的是 bev 拼接结果,真值 json 数据,以及将真值 json 数据画在拼接图像上的结果,其中:蓝色圆形空心点为停车位可见内角点;红色圆形空心点为停车位不可见内角点;绿线框为停车位外包围盒;白线框为左右边线的包围盒。 BEV 拼接效果如下图示例: ![](images/112_Synthetic_Data_Generation/image32.png) 采用`--show_json_on_img True`时会将 json 结果标注在最终的拼接图像中,如下图所示: ![](images/112_Synthetic_Data_Generation/image33.png) ##### 1.3.3.5 真值 json 数据格式说明 ###### 1.3.3.5.1 坐标系及旋转阵说明 首先说明各坐标系定义: 1. **世界坐标系原点**与地图一致,坐标轴与地图一致,即在用例编辑时,地图界面的向右方向为 X 轴正向,向上为 Y 轴正向,向屏幕外为 Z 轴正向。 2. **车体坐标系原点**与主车预览时显示一致,在两后车轮与地面接触点连线的中点;坐标轴方向也与主车预览时一致,车头方向为 X 轴正向,向左为 Y 轴正向,向上为 Z 轴正向。 3. **相机坐标系原点**与主车预览时一致;坐标轴方向,相机朝向正向为 X 轴正向,向左为 Y 轴正向,向上为 Z 轴正向。 4. **相机成像图像坐标系**,原点为左上角点,向右为 U 轴正向,向下为 V 轴正向。 然后是旋转阵定义,所有的旋转阵均为外旋矩阵,此处不做额外说明。 ###### 1.3.3.5.2 BEV 转换工具结果格式说明 经过转换工具转换后,dump 数据会转换为 BEV 图像,json 真值数据,这里对 json 真值数据的各部分进行说明。 1. **车辆信息** ```json "egocar info" 内保存的为车辆信息,包含车辆位置和旋转。 "egocar position": 车辆在世界坐标系中的坐标。 "egocar rotation": 车辆围绕世界坐标系的旋转,弧度制 ``` 2. **相机信息** ```json "camera info" 内保存的为相机信息,包含四个方向的相机内外参等信息。 "name":相机的名称,有"front","back","right","left" "camera position": 相机在世界坐标系下的坐标 "camera rotation": 相机在世界坐标系下的旋转 "camera_matrix": 相机的内参矩阵 "dist_coeffs": 相机的畸变参数矩阵 "resolution": 相机的画幅 "project_matrix": 相机在 BEV 拼接时的单应矩阵 "scale_xy": BEV 拼接时对相机图像的缩放 "shift_xy": BEV 拼接时对相机图像的移位 ``` 3. **停车位信息** ```json "parking_info"内保存的为停车位信息,包含在 BEV 图像上所有的可见停车位的信息 "ParkingSpace_id": 停车位自身的 ID,例如"1682", "World_Parking_InnerCorner_boundary": 停车位内角点在世界坐标系下的坐标 "UV_Parking_InnerCorner_boundary": 停车位内角点在 BEV 拼接结果图像的像素坐标 "Parking_InnerCorner_visibility": 停车位内角点是否可见的 flag,1 为可见,0 为被遮挡,2 为超出 BEV 视野。 "World_Parking_OutCorner_boundary": 停车位外拐角点在世界坐标系下的坐标 "UV_Parking_OutCorner_boundary": 停车位外拐角点在 BEV 拼接结果图像的像素坐标 "World_Parking_CenterCorner_boundary": 停车位标志线中线拐点在世界坐标系下的坐标 "UV_Parking_CenterCorner_boundary": 停车位标志线中线拐点在 BEV 拼接结果图像的像素坐标 "World_Parking_PaintLeft_boundary": 停车位左标志线的包围盒在世界坐标系下的坐标 "UV_Parking_PaintLeft_boundary": 停车位左标志线包围盒在 BEV 拼接结果图像的像素坐标 "World_Parking_PaintRight_boundary": 停车位右标志线包围盒在世界坐标系下的坐标 "UV_Parking_PaintRight_boundary": 停车位右标志线包围盒在 BEV 拼接结果图像的像素坐标 ``` ###### 1.3.3.5.3 原始 dump 数据格式说明 当制作自己的 BEV 拼接算法时,需要从原始的各路的 dump 数据开始进行,dump 数据输出路径中,一次任务的文件夹中会有鱼眼相机的子文件夹,鱼眼相机子文件夹中有输出的各帧数据,每一帧对应的文件夹内包含如下4个文件: ![](images/112_Synthetic_Data_Generation/image34.png) 其中 LaneInfo.json 就是这个相机输出的真值数据,打开后可主要分为以下几个部分,在这里简单分别论述一下。 1. **车辆及相机信息** 主要是车辆和相机信息。 ```json "camera intrinsic": 相机内参 "camera position": 相机的世界坐标系位置 "camera rotation": 相机在世界坐标系下的旋转 "egocar position": 车体的世界坐标系位置 "egocar rotation": 车体在世界坐标系下的旋转 ``` 2. **停车位信息** 在 json 文件中的"laneMark\_ParkingSpaces"项中,是停车位的相关信息。 ```json "ParkingSpace_Pos": 停车位世界坐标系位置 "ParkingSpace_Roadid": 停车位所属的道路 ID,由 open drive 地图得到,例如"1895", "ParkingSpace_heading": 停车位的世界坐标系朝向 "ParkingSpace_id": 停车位自身的 ID "Parking_InnerCorner_boundary": 停车位内拐角的相机坐标系坐标 "Parking_InnerCorner_projection": 停车位内拐角在相机成像图像中的像素坐标 "Parking_InnerCorner_visibility": 停车位内拐角是否可见的 flag 值,1 为可见,0 为被遮挡,2 为超出相机视野。 "Parking_OutCorner_boundary": 停车位外拐角点在相机坐标系坐标 "Parking_OutCorner_projection": 停车位外拐角点在相机成像图像中的像素坐标 "Parking_OutCorner_visibility": 停车位外拐角点是否可见的 flag 值。 "Parking_PaintLeft_boundary": 左边缘线包围盒角点在相机坐标系下的坐标 "Parking_PaintLeft_projection": 左边缘线包围盒角点在相机成像图像中的像素坐标 "Parking_PaintLeft_visibility": 左边缘线包围盒角点是否可见的 flag 值 "Parking_PaintRight_boundary": 右边缘线包围盒角点在相机坐标系下的坐标 "Parking_PaintRight_projection": 右边缘线包围盒角点在相机成像图像中的像素坐标 "Parking_PaintRight_visibility": 右边缘线包围盒角点是否可见的 flag 值 ``` 3. **车道线信息** 在 json 文件的"lane\_lines"一项中,是车道线相关信息,以 open lane 为基础定义。 ```json "attribute": 标识车道的左右属性,用于描述车道在整个道路中的位置。具体来说,不同的整数值对应不同的左右属性,1: 表示车道是非常靠近整个道路的左侧;2: 表示车道位于整个道路的左侧;3: 表示车道位于整个道路的右侧;4: 表示车道是非常靠近整个道路的右侧;dump 输出一般为 0,为默认值,无意义。 "category": 车道线类型,例如:“8”,即意为该条车道线为黄色实线。 0: 未知类型 1: 白色虚线 2: 白色实线 3: 双白色虚线 4: 双白色实线 5: 左侧为白色虚线,右侧为白色实线 6: 左侧为白色实线,右侧为白色虚线 7: 黄色虚线 8: 黄色实线 9: 双黄色虚线 10: 双黄色实线 11: 左侧为黄色虚线,右侧为黄色实线 12: 左侧为黄色实线,右侧为黄色虚线 20: 左侧靠近路缘 21: 右侧靠近路缘 "track_id": 车道线编号,例如"1330_0_-1_l",意为”1330”道路的”-1”号车道的左车道线 "uv":车道线各点在相机成像图像中的像素坐标 "visibility": 车道线各点是否可见的flag值 "xyz":车道线各点在相机坐标系下的坐标 ``` ##### 1.3.3.6 BEV 拼接算法简要说明 BEV 拼接的**基本原理**是通过将四个方向的图像,通过单应矩阵计算变换,投影到俯视视角,算法的基本流程可以概括为,设计最终 **BEV 范围**→**各方向标定**→**矫正各向鱼眼相机图像**→**投影各向相机图像**→**平滑交叠区域**→**得到最终的 BEV 拼接图像**。 **需要强调的是**,四路鱼眼相机图像通过单应矩阵进行图像变换,可以**正常拼接成为 BEV 图像的前提是**,**图像内容在同一平面内**,**否则可能会出现**,**具有高程的物体**,**在不同方向的视场交叠处出现重影的问题**,这是由单应矩阵变换的基本原理所导致的,无法去除。或是可以更改策略以规避重影问题,在平滑交叠区域时,不使用平滑策略而直接拼接,重叠处只保留单方向结果,但这同样会有不够平滑,高程物体在接缝处有跳变的现象,如果取舍可以根据需要。 json 真值部分主要是将不同坐标系进行变换,通过将 dump 原始数据中的相机坐标系坐标转换至世界坐标系,得到最终汇总的结果,较为简单。 其中的技术细节可以使用**单应矩阵**,BEV 等作为搜索关键词自行了解,这里不过多赘述。 ##### 1.3.3.7 异常数据的特殊处理 由于 BEV 拼接算法的本身缺陷,对于有高程的物体在拼接结果中,可能出现虚影,此时对于部分标注物来说,可能在某个方向可见而另一个方向不可见的情况,此时对于 BEV 拼接结果中的是否可见,需要根据自己的需求进行判断。 转换工具的 json 最终结果可能就与需求不同,需要从各方向鱼眼相机的原始”LaneInfo.json”信息,取得各个方向的真值,按照自己的需求进行数据过滤和 BEV 拼接。