云服务器内容精选
-
数据资产简介 在自动驾驶产品的开发过程中,海量的数据存储和管理是当前自动驾驶平台面临的业务挑战之一。 Octopus平台的数据服务模块提供了海量数据采集、存储以及数据并行处理等功能,供后续服务进行统一使用。数据服务开发流程如下: 图1 数据服务开发流程 地图管理:支持上传高精地图数据,可用于数据回放、仿真场景等功能。 标定管理:支持车辆、车辆传感器标定的配置,方便即时管理车辆以及标定信息。 源数据包:此模块展示导入成功的数据包,支持对源数据包的查看,回放等功能。 数据场景:平台处理完原始采集数据后,平台支持内置和自定义场景挖掘算法,可自动提取对应场景行为的片段,展示在此模块中。 数据集:支持数据集多版本管理和统计。同时支持用户将本地符合平台规范的数据集导入平台,以及将平台上的数据集导出到自有OBS桶中。 数据缓存:提供专用高速文件存储功能,加速训练和评测读取数据集的速度。 模型管理:负责对模型仓库和模型版本进行各种操作,模型仓库可包含多个模型版本,支持上传符合平台规范的模型用于标注或训练任务。 通用存储:支持创建通用存储,用于数据存储。 父主题: 数据资产
-
执行顺序(Execution sequence) OSC2.0场景剧本StoryBoard通过执行顺序Execution Sequence和触发器Trigger来支持用户设计各种场景。StoryBoard中有parallel和serial两种执行指令,最外层执行指令之前需要加上do来使场景剧本生效。其中: parallel:同步执行下方代码块内的动作action。 serial:依次执行下方代码块内的动作act。 例如下方样例中,do parallel:下的assign_init_speed,assign_init_position和wait elapsed(10s) 是同步执行的。而serial:下的lead_vehicle.change_speed在Ego.activate_controller完成之后执行。 由于初始动作InitAction内的action同步执行,且InitAction与story之间不涉及顺序执行,建议场景最外层统一使用parallel。 样例 m_profile: dynamics_shape = linear do parallel: # InitAction Ego.assign_init_speed(15mps) Ego.assign_init_position(position: Ego_InitPosition) # Story serial: # act1 Ego.activate_controller(true, true) lead_vehicle.change_speed(target: 20mps, rate_profile: m_profile, rate_peak: 0.3mpss) serial: # act2 wait elapsed(10s) lead_vehicle.activate_controller(true, true)
-
绘制对象 绘制多边形。 选择左侧工具栏多边形按钮绘制多边形。 选择标注。 标注列表页选择符合的标注。 绘制标注形状。 绘制标注形状有两种方法:点式绘制和交互式分割工具,用户可根据需要选择绘制方式 点式绘制形状:通过单击目标对象的边缘,点状连线,获得闭合的多边形,操作如下: 通过鼠标左键单击添加点标注图中对象,未闭合状态可通过“alt+Z”撤销上一步绘制的点,标注过程中可通过“alt+鼠标左键”拖动图片。按住键盘上空格键进行闭合,该对象标注完成。 项目类型为语义标注、道路特征提取、可行驶区域,这三类任务是空格键闭合且alt+鼠标左键拖动图片,其余任务使用左键拖动图片和闭合多边形。 交互式分割工具(仅在“语义标注”项目中使用):通过在标注对象及附近区域单击正点(目标对象区域的点)或负点(非目标对象区域的点), 自动得到较优的多边形。具体步骤如下: 单击快捷键“4,非小键盘”,进入多边形绘制状态。 单击快捷键“z”键进入目标对象的交互式标注模式, 页面右上角出现“交互式分割已开启”字样。 在前景区域,通过鼠标左键单击正点(目标对象区域的点),得到预测的多边形。 图1 单击正点 在背景区域,通过鼠标左键单击负点(非目标对象区域的点),修正多边形。在多边形区域未包含的前景区域左键单击正点,修正多边形。 图2 单击负点 重复单击正或负点,修正预测的多边形,直到多边形达到较好的效果。 图3 修正预测的多边形 一般情况下,单击3-5个点即可达到较好效果,如果超过10个点还未达到较好效果,则此对象的此次交互式标注基本无效,建议退出。 再次单击快捷键“z”键,可退出目标对象的交互式标注模式, 页面右上角“交互式分割已开启”字样消失。该对象标注完成。 切割线工具修改多边形。 单击左侧标注工具栏切割线(快捷键8,非小键盘),切割线空格键闭合,切割线绘制完成通过键盘上“m”键可完成切割。 切割线可用于切割多边形不贴合部分,切割线首尾两点与多边形需有交点。 其他常用标注工具。 绘制共边对象:通过键盘上“X”键实现两对象共边。 图4 绘制共边对象 图5 绘制共边对象效果 全局标注:选中一标注对象,单击左侧工具栏“全局标注物”按钮,或通过键盘快捷键“i”复制该对象到图层中,选中该对象可应用到本图或者下一张图中。该步骤可用于有相同对象的图片,或者有覆盖类型的标注中。 图6 全局标注 删除对象:选中一对象,通过键盘上“delete”键可在图中删除该对象。 撤回上一步:单击左侧工具栏“撤回”,或通过快捷键“Ctrl+z”撤回上一步。 隐藏标注列表和预览图:单击左侧工具栏“隐藏标注列表”、“隐藏预览”,扩大标注区域。 调整透明度:单击左侧工具栏“调整透明度”,调整图片。 更改标注类别。 多边形闭合后可在该对象上单击鼠标左键,更改该对象类别。 修改额外属性。 左键单击目标图形,如果目标含有额外属性,如果其默认属性错误,单击即可选择属性。 修改对象ID。 左键单击目标图形,可以在对象ID栏手动输入数值来修改ID。
-
split 简述:地图场景为匝道分流。lead_vehicle和主车Ego在主道的同一车道上分别以35kph和Ego_InitSpeed_Ve0的初始速度一前一后行驶,Ego设定了目标在匝道上的目标点Target_position,仿真开始后激活Ego控制器(控制器会影响Ego去往Target_position的寻路算法,但目前仿真器B尚不支持寻路动作acquire_position)。控制器有时会根据lead_vehicle的位置更改主车Ego的速度。 使用xyz坐标创建终点时,由于匝道地图泛化会使终点偏移,建议在创建测评任务时为检测终点设置合适的半径,例如"到达半径5m"。 地图文件(odr) scenario Split: m_scene: scenery lane_width: length = [3m..4m] main_speed: speed = 120kph ramp_speed: speed = 60kph ramp_length: length = [300m..350m] road_aids_type: road_aids_type = "DType-2" split_1: split with: keep(it.lane_width == lane_width) keep(it.left_lane_num == 0) keep(it.right_lane_num == 3) keep(it.ramp_lane_num == 1) keep(it.main_speed == main_speed) keep(it.ramp_speed == ramp_speed) keep(it.radius_of_curvature == 200m) keep(it.ramp_length == ramp_length) keep(it.road_aids_type == road_aids_type) 场景文件(osc) import standard scenario Split: # map map: map map.set_map_file("./split.odr") # parameter Ego_InitSpeed_Ve0: speed = [90kph..110kph] Ego_InitPosition_LaneId: string = ['-1', '-2'] Ego_InitPosition_s: length = [0m..100m] Ego_Odr: odr_point = map.create_odr_point(road_id: '10', lane_id: Ego_InitPosition_LaneId, s: Ego_InitPosition_s, t: 0.0m) Ego_InitPosition: pose_3d with: keep(it.odr_point == Ego_Odr) m_InitDistance: length = [60m..100m] Target_xyz: xyz_point = map.create_xyz_point(x: 445m, y: -46.5m ,z: 0.0m) Target_position: pose_3d with: keep(it.xyz_point == Target_xyz) Duration: time = 100s # entity Ego: vehicle with: keep(it.name == "Saimo") keep(it.initial_bm == "默认驾驶员") lead_vehicle: vehicle with: keep(it.name == "Saimo") keep(it.initial_bm == "默认驾驶员") # storyboard do parallel(duration: Duration): # init Ego.assign_init_position(position: Ego_InitPosition) Ego.assign_init_speed(Ego_InitSpeed_Ve0) lead_vehicle.assign_init_position() with: lane(same_as: Ego) position(distance: m_InitDistance, ahead_of: Ego) lead_vehicle.assign_init_speed(35kph) Ego.activate_controller(true, true) Ego.acquire_position(target: Target_position) 父主题: 种子地图的逻辑场景样例(仿真器B)
-
注册华为账号 并开通华为云 在使用华为云服务之前您需要申请华为云账号并进行实名认证。通过此账号,您可以使用所有华为云服务,并且只需为您所使用的服务付费。 如果您已有一个华为云账号,请跳到下一个任务。如果您还没有华为云账号,请参考以下步骤创建。 打开华为云官网,单击“注册”。 根据提示信息完成注册,详细操作请参见注册华为账号并开通华为云。 注册成功后,系统会自动跳转至您的个人信息界面。 参考实名认证完成个人或企业账号实名认证。 父主题: 准备工作
-
OCTOPUS格式文件基本要求(文本标注) 上传的OCTOPUS格式数据集需包含以下文件(以txt格式为例)。文本文件支持的格式包含:txt、yaml、xml、csv。 . ├─ 文件夹1 ├─ text1.txt #文本文件 ├─ text1.json #该文本文件的所有标注信息 ├─ 文件夹2 ├─ text2.txt #文本文件 ├─ text2.json #该文本文件的所有标注信息
-
标注数据.json文件说明 数据集中必含“.json”文件,用于集合该文本文件的所有标注数据信息,包括该文本所在的项目id、数据包id、文本上所有标注信息等。上传数据集前请保证“.json”文件内容正确。“.json”文件编写的参考样例如下: { "frame_id": 1, #帧序号 "batch_task_id": 1368, #批次任务id "project_id": "ee...3d", #资源域ID "label_mode": "manual", #标注类型:auto和manual两种 "status": "labeled", #标注任务状态:unlabeled、labeled、unconfirmed、confirmed、all五种 "sample_type": "TEXT", #样本类型:包含“IMAGE”,“POINT_CLOUD”,“AUDIO”,“TEXT” "des_order": "", #此份数据对应的原始数据包描述 "tag_names": [], #标签名称 "valid": true, #是否有效,包含“true”和“false”两种 "create_time": 1708657733087, #标注的创建时间 "difficult": false, #是否难例,包含“true”难例和“false”非难例 "label_counts": [ #各类标注物的个数统计 { "label_meta_id": 7900, #标注物使用的标签ID "label_num": 1, #标注物个数 "label_meta_name": "人物", #标注物名称 "label_meta_desc": "1233", #标注物描述 "label_meta_attr": "{\"男\":\"少年,青年\",\"女\":\"少年,青年\"}", #标注物额外属性 "label_meta_shape": "text", #标注物形状,包含“bndbox、line、circle、polygon、points、dashed、cube_3d、multiBox、polygon_3d_v2、audio、text” "label_meta_color": "#496832", #标注物颜色信息 "level": 0 }, { "label_meta_id": 7901, "label_num": 1, "label_meta_name": "水果", "label_meta_desc": "11", "label_meta_attr": "{\"颜色\":\红,黄\"}", "label_meta_shape": "text", "label_meta_color": "#391c1c", "level": 0 } ], "text_meta_info": { #文本信息 "id": "49...bd", "name": "0000.txt", #文本名称 "source": "https://octopus-raw-ee.../label-data/task-1368/data/txt/0000.txt" #音频源的obs路径url }, "label_task_id": 1691, #批次子任务ID "partitionId": 20240222, "label_update_time": 1708944569975, #标注最近更新时间 "prefix_folder": "txt", "image_id": "88...91", "inspection": 0, "labels": [ { "label_meta_id": 7900, #标注物对应的标签ID "create_time": 0, "shape_type": "text", #标注物形状 "serial_number": 1, #该帧中标注物唯一自增id "label_object_id": -1, "attribute": "{\"人物\":\"男\"}", #标注物属性 "text": { #文本标注信息 "start_idx": 1, #标注起始偏移量 "end_idx": 3 #标注结束偏移量 }, "label_meta_name": "人物" #标注物名称 } ] }
-
eva.proto的关键字段解释 在利用Octopus仿真平台进行批量仿真时,每个场景都会有一个评测结果,单个场景的评测结果全部保存在如数据类图所示的Evaluation类中。 Evaluation类包含以下的7个字段。 表1 Evaluation类包含的字段 字段 说明 version 用于表示当前Octopus_eva.proto的版本。 score 用户保存批量仿真中单个场景下评测算法计算出的评测得分,Octopus的评分取值为[0, 100]。 avg_speed 单个场景下自动驾驶算法控制下主车的平均车速,单位m/s。 distance 单个场景下自动驾驶算法控制下主车的行驶里程,单位m。 vis 主车关键状态量的(如速度、加速度)的时间序列数据,用于前端进行可视化曲线展示。 metrics Octopus内置了一批大类评测指标,并且每个大类评测指标下会多个子类指标。 该字段用于保存每个大类和子类评测指标的通过/未通过/无效的结果状态。 其中无效状态表示该指标在特定场景下是没意义的,如在没有交通灯的场景下,主车在交通灯前的行为检测是没有意义的。 source 是一个Source枚举类型,表示该评测算法的结果来源类型。 source共有6种类型,具体参考source。 表2 source 字段 说明 SOURCE_UNSPECIFIED 表示评测算法类型未定义。 SOURCE_CUSTOMIZED_REALTIME 用户自定义实时评测算法结果。 SOURCE_CUSTOMIZED_OFFLINE 用户自定义延时评测算法结果。 SOURCE_DEFAULT_REALTIME 八爪鱼内置实时评测算法结果。 SOURCE_DEFAULT_OFFLINE 八爪鱼内置延时评测结果。 SOURCE_MERGED 融合后的评测结果。 Evaluation中两个比较关键且复杂的字段是vis和metrics,其中vis字段类型是Visualization,metrics字段的类型是repeated Metric。 Visualization和Metric的成员组成如上数据类图所示,各个关键成员的含义如下所示。 Visualization类型包含的各个字段及其含义如下所示。 表3 Visualization类型字段 字段 说明 sim_times 仿真过程的时间序列点,以仿真开始时刻(t0)为0点,相邻时刻的时间间隔为仿真器的周期,单位为秒(s)。 frame_nums 每个仿真时刻对应的数据帧数,表明这是第几帧的数据。 stats 统计类型的数据值,是指某数据在一段时间内统计值才有展示分析的意义,如加速度均方根值(arms),随着仿真时刻不断后移,需要不断计算初始时刻(t0)到当前仿真时刻(t)的arms值。 stats字段的类型是Statistic,Statistic类型的成员具体参考stats。 vector 向量类型的数据值,是指每个时刻都会有一个对应的数据值,如加速度、速度等物理量。 vector字段的类型是Vector,Vector类型的成员具体参考vector。 表4 stats 字段 说明 type 是一个Type的枚举类型,表示该数据是哪种Octopus内置的Statistic类型。 value 该数据在每个仿真时刻对应的数值。 display_name 存储用户自定义的Statistic类型名称,用户自定义的数据无需对type赋值。 source 表示该数据的评测结果来源类型。 importance 表示该数据是重要类型还是次要类型。 module 表示该数据是来源于哪个算法模块。 performance 表示该数据是表示的哪个类别的算法性能。 表5 vector 字段 说明 type 是一个Type的枚举类型,表示该数据是哪种Octopus内置的Vector类型。 value 该数据在每个仿真时刻对应的数值。 display_name 存储用户自定义的Vector类型名称,用户自定义的数据无需对type赋值。 source 表示该数据的评测结果来源类型。 importance 表示该数据是重要类型还是次要类型。 module 表示该数据是来源于哪个算法模块。 performance 表示该数据是表示的哪个类别的算法性能。 Metric类型包含的各个字段及其含义如下所示。 表6 Metric类型字段 字段 说明 type 是一个Enum类型,表示该数据是哪种Octopus内置的大类指标类型。 status 是一个Result的枚举类型,用于表示该大类指标的评测结果。 其中Result有三种类型,分别为: RESULT_UNSPECIFIED:该状态的结果表示评测指标是无效的,如对于红绿灯检测指标,如果仿真完成后评测函数发现场景中不存在红绿灯,则该项指标的评测是没有意义的,故评测结果展示为无效。 RESULT_PASSED: 该状态的结果表示评测结果为通过。 RESULT_FAILED:该状态的结果表示评测结果为未通过。 anomalies 用于保存每个大类指标下对应的子类指标发生异常的时间点,其数据类型为repeated Anomaly,其中Anomaly类型成员如下所示: status: 是一个Result类型,与上述大类指标的status的表示相同,该字段用于存储子类指标的三种不同状态结果。 subtype:是一个Subtype的枚举类型,表示该子类指标是哪种Octopus内置的子类指标类型。 其中,对于某些没有子类指标的大类指标来说,其subtype赋值为SUBTYPE_UNSPECIFIED。 point_type:是一个PointType的枚举类型,表示该子类指标发生特殊状态(一般是指发生异常)时的时刻点用哪种形式存储起来。 其中PointType共有5种类型,参考PointType。 Points:是repeated float类型,保存每个子类指标发生特殊状态的具体时间点的值。 Stats_indices:是repeated ui32类型,表示该子指标关联的统计类数值列表。 Vector_indices:是repeated ui32类型,表示该子指标关联的时间序列数值列表。 display_name 存储用户自定义的Anomaly类型名称,表示其自定义的子类指标,用户自定义的数据无需对sub_type赋值。 importance 表示该指标的重要程度。具体参考importance。 source 表示该数据的评测结果来源类型。 module 表示该数据是来源于哪个算法模块。具体参考module。 performance 表示该数据是表示的哪个类别的算法性能。具体参考performance。 表7 PointType 字段 说明 POINT_TYPE_UNSPECIFIED 未定义的类型,遵循proto定义格式,Octopus未使用该类型,用户可根据需要对该类型赋予特定含义。 POINT_TYPE_POINT 表示该子类指标的异常时间点是离散的时间点形式,在任何时刻都可能发生异常。 POINT_TYPE_REGION 表示该子类指标的异常时间点是区间形式,一旦在某个时刻开始发生异常,则在随后一段时间内都会处于异常状态。 POINT_TYPE_ALL 表示该类指标的异常时间点是布尔形式的,从仿真开始到当前时刻的状态要么是完全通过,要么全过程都是异常的,统计类型的指标需要以这种形式表示。 POINT_TYPE_NORMAL 该类型与其他类型相反,如果该类型的点存在,则表示对应的子类指标是通过的,Octopus用该类型保存主车到达终点的时间值。 表8 importance 字段 取值 说明 CATEGORY_UNSPECIFIED 0 未定义 CATEGORY_MAJOR 1 主要 CATEGORY_MINOR 2 次要 表9 module 字段 取值 说明 MODULE_UNSPECIFIED 0 未定义 MODULE_NAVIGATION 1 导航 MODULE_LOCATION 2 定位 MODULE_PERCEPTION 3 感知 MODULE_PREDICTION 4 预测 MODULE_DECISION 5 决策 MODULE_PLANNING 6 规划 MODULE_CONTROL 7 控制 MODULE_WHOLE 8 整车 表10 performance 字段 取值 说明 PERFORMANCE_UNSPECIFIED 0 未定义 PERFORMANCE_SAFETY 1 安全性 PERFORMANCE_REGULATION 2 合规性 PERFORMANCE_COMFORT 3 舒适性 PERFORMANCE_INTELLIGENCE 4 智能型
-
背景 Octopus内置一套评测算法,用于对自动驾驶系统的性能表现进行多维度评测。内置评测算法的评测结果按照eva.proto中的定义,序列化成pb文件保存起来。 Octopus仿真平台的前端通过解析评测pb对评测结果进行展示,目前控制台展示主要分为两大方面: 各个评测指标的通过/未通过/无效的结果展示。 仿真过程中关键数据的时间序列曲线图展示。 另外,对于用户自研的评测算法的评测结果,也可以按照eva.proto,序列化成pb文件保存起来,这样Octopus的仿真平台前端能够展示用户自研评测算法的评测结果。
-
上传数据包 获取传输配置。 在订单的“操作”列单击“获取传输配置”,获取传输配置,包括目标桶、导入目录、访问密钥 (AK)和私有访问密钥 (SK)。 准备待脱敏的数据包。 图商采集的数据在上传至八爪鱼平台前,需要对数据包中的文件夹梳理,便于脱敏识别,目录层级需为“根目录/数据存放文件夹”,根目录需为3创建的订单号。 上传至八爪鱼平台后数据路径:data/import-expresses/根目录/数据存放文件夹 例如:data/import-expresses/24/packge-1 24:根目录,即3创建的订单号。 packge-1:需要脱敏的数据存放文件夹。订单号和实际需要脱敏的文件夹之间不需要再加层级。 脱敏任务完成后平台存储的原始数据和脱敏后数据路径如下: 原始数据:data/import-expresses/24/packge-1-bak 脱敏后数据:data/import-expresses/24/packge-1 上传待脱敏的数据包。 在DES数据快递服务创建递送订单,并完成递送订单。DES订单上传源数据需要包含必要的有效文件,具体可参考上传数据格式。 数据上传完成后,单击“确认递送完成”,单击“确定”。
-
评测任务相关操作 在“评测任务”列表,可对任务进行以下操作。 表4 评测任务相关操作 任务 操作步骤 查找任务 在搜索输入框中输入搜索条件,按回车键即可查询。 查看任务详情 单击任务名称,可在任务详情页查看该任务详情、参数信息、评测结果、任务日志和资源在占用情况。 任务详情:任务ID、名称、描述、状态、资源类型等信息。 任务视图:根据创建任务时选择不同的评测,显示不同的任务视图。 评测结果:单击任务视图,可显示相对应的评测任务结果,详情请参考评测结果。 任务日志:单击任务视图,可显示相对应的任务运行过程中生成的日志信息,详情请查看评测任务日志查看与下载。 资源占用情况:单击任务视图,可显示相对应任务占用的CPU、内存、GPU显存利用率、占用率百分比的折线图,详情请查看资源占用情况。 删除任务 单击操作栏的“删除”,删除单个任务。 勾选多个任务,单击列表上方的“删除”,可批量删除任务。 重建任务 单击操作栏内的“重建”,输入新任务名称(以“任务组名-自定义名称”的形式)和是否删除原任务选项,同时可重新选择需要修改的参数。 停止任务 单击操作栏的“停止”,停止评测任务。 继续任务 单击操作栏中的“继续”,继续执行任务。 对比任务 勾选2-4个任务(要求类别相同,且均为已完成状态),单击“对比”创建对比任务,具体步骤请参考评测对比。
-
构建镜像 Dockerfile示例 FROM python:3.10 COPY mask.py /home/main/ WORKDIR /home/main/ RUN pip install rosbags requests numpy USER root 构建镜像 sudo docker build --no-cache -f Dockerfile -t rosbagmask:0.1 . 本地调试 准备一个待处理的rosbag包。 sudo docker run -v ${HOME}/data/test.bag:/home/main/test.bag --env input_file=/home/main/test.bag –env raw_dir=/home/main/raw_dir –env desensitized_dir=/home/main/desensitized_dir –env output_dir=/home/main/output_dir -it rosbagmask:0.1 /bin/sh -c "python mask.py"
-
示例代码 下面是rosbag脱敏的算子示例: # mask.py import json import logging import multiprocessing as mp import os import shutil import time from pathlib import Path from typing import cast import av import numpy as np import open3d from rosbags.highlevel import AnyReader from rosbags.interfaces import ConnectionExtRosbag1, ConnectionExtRosbag2 from rosbags.rosbag1 import Writer as Writer1 from rosbags.rosbag2 import Writer as Writer2 from rosbags.serde import cdr_to_ros1, serialize_cdr from rosbags.typesys import get_types_from_msg, register_types from rosbags.typesys.types import builtin_interfaces__msg__Time as Time from rosbags.typesys.types import \ sensor_msgs__msg__CompressedImage as CompressedImage from rosbags.typesys.types import std_msgs__msg__Header as Header logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', ) LOG = logging.getLogger(__file__) # Octopus数据服务拉起镜像时灌入的环境变量 # 获取环境变量 input_path = os.getenv('input_path', 'data/hangyan-move.bag.bak') raw_dir = os.getenv('raw_dir', 'empty_dir/raw') # 抽取的文件存放目录 desens_dir = os.getenv('desensitized_dir', 'empty_dir/desens') # 脱敏后的文件存放目录 output_dir = os.getenv('output_dir', 'empty_dir/output') lidar_process_num = os.getenv('lidar_process_num', 5) # lidar数据进程数 # 用户自定义环境变量 rosbag_version = os.getenv('rosbag_version', '1') # rosbag版本,取值为'1'或'2' image_topics = [ x.strip(' ') for x in os.getenv('image_topics', '/camera_encoded_1').split(',') ] # 图像数据的topic列表 gnss_topic = os.getenv('gnss_topic', '/inspvax') # gnss数据的topic,gnss数据只能有一个topic lidar_topics = [ x.strip(' ') for x in os.getenv('lidar_topic', '/pandar').split(',') ] # 点云数据的topic列表 # 注册自定义消息类型 Video_encoded_data_text = Path('msgs/Video_encoded_data.msg').read_text() NovatelMessageHeader_text = Path('msgs/NovatelMessageHeader.msg').read_text() NovatelExtendedSolutionStatus_text = Path( 'msgs/NovatelExtendedSolutionStatus.msg').read_text() NovatelReceiverStatus_text = Path('msgs/NovatelReceiverStatus.msg').read_text() Inspvax_text = Path('msgs/Inspvax.msg').read_text() add_types = {} add_types.update( get_types_from_msg( Video_encoded_data_text, 'kyber_msgs/msg/Video_encoded_data', )) add_types.update( get_types_from_msg( NovatelMessageHeader_text, 'novatel_gps_msgs/msg/NovatelMessageHeader', )) add_types.update( get_types_from_msg( NovatelExtendedSolutionStatus_text, 'novatel_gps_msgs/msg/NovatelExtendedSolutionStatus', )) add_types.update( get_types_from_msg( NovatelReceiverStatus_text, 'novatel_gps_msgs/msg/NovatelReceiverStatus', )) add_types.update( get_types_from_msg( Inspvax_text, 'novatel_gps_msgs/msg/Inspvax', )) register_types(add_types) # create gnss file gnss_file_path = Path(raw_dir, 'gnss') / f'{gnss_topic}.json'.strip('/') Path.mkdir(gnss_file_path.parent, parents=True, exist_ok=True) def extract_image(input_rosbag): '''从原始rosbag中抽取图像数据.''' LOG.info('Start extracting image.') codec_ctx = av.codec.Codec('hevc', 'r') h265_code = codec_ctx.create() with AnyReader([Path(input_rosbag)]) as reader: for connection, timestamp, data in reader.messages(): topic = connection.topic if topic in image_topics: deserialized_data = reader.deserialize(data, connection.msgtype) try: data = deserialized_data.raw_data packet = av.packet.Packet(data) out = h265_code.decode(packet) img = None for frame in out: if frame.format.name != 'rgb24': frame = frame.reformat(format='rgb24') img = frame.to_image() # 图像存放路径 file_name = f'{timestamp}.jpg' f_path = Path(raw_dir, 'image') / topic.strip('/') tmp_path = Path(raw_dir, 'tmp_image') / topic.strip('/') Path.mkdir(tmp_path, parents=True, exist_ok=True) tmp_file = tmp_path / file_name file = f_path / file_name # 当未建立目录时,先基于topic名称建立目录 Path.mkdir(file.parent, parents=True, exist_ok=True) img.save(tmp_file) os.chmod(tmp_file, 0o777) os.chmod(file.parent, 0o777) shutil.move(tmp_file, file) except Exception as e: LOG.info("%s frame can not trans to jpg, message: %s", timestamp, str(e)) LOG.info('Finish extracting image.') def extract_lidar(task_id, task_num, input_rosbag): '''从原始rosbag中抽取点云数据.''' LOG.info('Start extracting pcd.') with AnyReader([Path(input_rosbag)]) as reader: for i, (connection, timestamp, data) in enumerate(reader.messages()): if i % task_num != task_id: continue topic = connection.topic if topic in lidar_topics: deserialized_data = reader.deserialize(data, connection.msgtype) pcd = open3d.geometry.PointCloud() reshaped = deserialized_data.data.reshape( int(len(deserialized_data.data) / 3), 3) pcd.points = open3d.utility.Vector3dVector(reshaped) file_name = f'{timestamp}.pcd' f_path = Path(raw_dir, 'lidar') / topic.strip('/') tmp_path = Path(raw_dir, 'tmp_lidar') / topic.strip('/') Path.mkdir(tmp_path, parents=True, exist_ok=True) tmp_file = tmp_path / file_name file = f_path / file_name # 当未建立目录时,先基于topic名称建立目录 Path.mkdir(file.parent, parents=True, exist_ok=True) open3d.io.write_point_cloud(str(tmp_file), pcd) os.chmod(tmp_file, 0o777) os.chmod(file.parent, 0o777) shutil.move(tmp_file, file) LOG.info('Finish extracting pcd.') def extract_gnss(input_rosbag): '''从原始rosbag中抽取gnss数据.''' LOG.info('Start extracting rosbag.') gnss_file = open(gnss_file_path, 'w') gnss = dict() with AnyReader([Path(input_rosbag)]) as reader: for connection, timestamp, data in reader.messages(): topic = connection.topic if topic == gnss_topic: deserialized_data = reader.deserialize(data, connection.msgtype) # 这里以msgytpe为NavSatFix为例 latitude = deserialized_data.latitude longitude = deserialized_data.longitude altitude = deserialized_data.altitude gnss[timestamp] = { 'latitude': latitude, 'longitude': longitude, 'altitude': altitude } gnss_file.write(json.dumps(gnss)) gnss_file.close() LOG.info('Finish extracting gnss.') def _get_masked_image(topic, timestamp): '''从脱敏后的图像数据中获取目标图像数据.''' file = Path(desens_dir, 'image') / topic.strip('/') / f'{timestamp}.jpg' if file.is_file(): return np.fromfile(file, dtype='uint8') else: return None def _get_conn_map(rosbag_version: int, reader, writer): '''构建connection的索引.''' conn_map = {} if rosbag_version == '1': for conn in reader.connections: if conn.topic in image_topics: conn_map[conn.id] = writer.add_connection( '/image', CompressedImage.__msgtype__, ) else: ext = cast(ConnectionExtRosbag1, conn.ext) conn_map[conn.id] = writer.add_connection( conn.topic, conn.msgtype, conn.msgdef, conn.md5sum, ext.callerid, ext.latching, ) elif rosbag_version == '2': for conn in reader.connections: if conn.topic in image_topics: conn_map[conn.id] = writer.add_connection( '/image', CompressedImage.__msgtype__, ) else: ext = cast(ConnectionExtRosbag2, conn.ext) conn_map[conn.id] = writer.add_connection( conn.topic, conn.msgtype, ext.serialization_format, ext.offered_qos_profiles, ) return conn_map def _serialize_data(rosbag_version, data, msgtype): '''对数据进行序列化.''' if rosbag_version == '1': return cdr_to_ros1(serialize_cdr(data, msgtype), msgtype) elif rosbag_version == '2': return serialize_cdr(data, msgtype) def generate_rosbag(input_rosbag, output_rosbag): '''生成脱敏后rosbag.''' LOG.info('Start generating rosbag.') gnss_file = open( Path(desens_dir, 'gnss') / f'{gnss_topic}.json'.strip('/'), 'r') gnss_data = json.load(gnss_file) gnss_file.close() Writer = Writer1 if rosbag_version == '1' else Writer2 with AnyReader([Path(input_rosbag) ]) as reader, Writer(Path(output_rosbag)) as writer: conn_map = _get_conn_map(rosbag_version, reader, writer) for connection, timestamp, data in reader.messages(): topic = connection.topic # 当topic为图像数据的topic时,读取脱敏后图像数据 if topic in image_topics: masked_data = _get_masked_image(topic, timestamp) if masked_data is None: # 没有解析出图像文件时,不要该帧了 continue deserialized_data = CompressedImage( Header( stamp=Time( sec=int(timestamp // 10**9), nanosec=int(timestamp % 10**9), ), frame_id='0', ), format='jpg', data=masked_data, ) data = _serialize_data( rosbag_version, deserialized_data, CompressedImage.__msgtype__, ) # 当topic为gnss数据时,读取脱敏后gnss数据 elif topic == gnss_topic: deserialized_data = reader.deserialize(data, connection.msgtype) deserialized_data.latitude = gnss_data.get( str(timestamp)).get('latitude') deserialized_data.longitude = gnss_data.get( str(timestamp)).get('longitude') deserialized_data.altitude = gnss_data.get( str(timestamp)).get('altitude') data = _serialize_data( rosbag_version, deserialized_data, connection.msgtype, ) # 当topic为点云数据时,读取脱敏后点云数据 elif topic in lidar_topics: deserialized_data = reader.deserialize( data, connection.msgtype, ) file = Path( desens_dir, 'lidar', ) / topic.strip('/') / f'{timestamp}.pcd' point_cloud = open3d.io.read_point_cloud(str(file)) deserialized_data.data = np.asarray( point_cloud.points).flatten() writer.write(conn_map[connection.id], timestamp, data) # 生成_SUC CES S文件标识完成数据抽取 Path(output_dir, '_SUCCESS').touch() LOG.info('Finish generating rosbag.') if __name__ == "__main__": LOG.info('Start user operator.') process_image = mp.Process(target=extract_image, args=(input_path, )) pool_lidar = mp.Pool(processes=lidar_process_num) for i in range(lidar_process_num): pool_lidar.apply_async(extract_lidar, args=(i, lidar_process_num, input_path)) process_gnss = mp.Process(target=extract_gnss, args=(input_path, )) # 启动子进程 process_image.start() pool_lidar.close() process_gnss.start() process_image.join() pool_lidar.join() process_gnss.join() LOG.info('Child processes exit.') # 生成_SUCCESS文件标识完成数据抽取 Path(raw_dir, '_SUCCESS').touch() # 后面输出的rosbag文件与输入的rosbag文件保持同名 output_rosbag_file = Path(output_dir, Path(input_path).name) # 如果输出文件夹不存在,先创建文件夹 Path.mkdir(output_rosbag_file.parent, parents=True, exist_ok=True) # 检测到脱敏任务结束后,生成新的rosbag文件 while time.sleep(1) is None: if Path(desens_dir).joinpath('_SUCCESS').is_file(): generate_rosbag(Path(input_path), output_rosbag_file) break
-
作业输入输出规范 用户完成自定义脱敏算子创建,运行作业容器时Octopus平台向其中注入以下环境变量: input_file:待脱敏的文件路径 raw_dir:抽取的image,gnss,lidar数据存放路径 desensitized_dir:脱敏后的image,gnss,lidar数据存放路径 output_dir:脱敏后的文件存放路径 用户根据需要可以自定义环境变量,以rosbag文件为例,可以定义如下环境变量: rosbag_version:robag版本 image_topics:图像数据topic列表 gnss_topic:gnss数据topic lidar_topics:lidar数据topic列表 用户作业容器需要将input_file中的image,gnss,lidar数据抽取到raw_dir,待系统内置算子脱敏完成,并将脱敏后的数据存放到desensitized_dir后,用户算子根据input_file和desensitized_dir中的脱敏数据生成新的数据文件存放到output_dir。 文件结构如下: -raw --image ---topic0 ----timestamp1.jpg ----timestamp2.jpg ---topic1 ----timestamp1.jpg --gnss ---gnss_topic.json --lidar ---pcd_topic0 ----timestamp0.pcd ----timestamp1.pcd --SUCCESS -desensitized --image ---topic0 ----timestamp1.jpg ----timestamp2.jpg ---topic1 ----timestamp1.jpg --gnss ---gnss_topic.json --lidar ---pcd_topic0 ----timestamp0.pcd ----timestamp1.pcd --SUCCESS -output --test.bag --SUCCESS 其中,“SUCCESS”文件为标识文件,标识所在阶段的任务结束。
-
场景库相关操作 在“场景库”页签,可对场景库进行以下操作。 表1 场景库相关操作 任务 操作步骤 查看场景库信息 单击左侧场景库名称,查看右侧该场景库信息以及场景库包含场景信息。 场景库信息:场景库名称、创建人、仿真器、描述、关联仿真任务数和创建时间等信息。 场景列表:该场景库中包含的所有场景。场景的具体操作请参考场景管理。 修改场景库信息/场景库分类信息 单击场景库名称或场景库分类后的,修改场景库或场景库分类的信息。 删除场景库/场景库分类 单击场景库名称或场景库分类后的,删除指定场景库或场景库分类。 查询场景 根据“场景名称”或“创建人”,输入搜索条件,查询场景列表中的场景。
更多精彩内容
CDN加速
GaussDB
文字转换成语音
免费的服务器
如何创建网站
域名网站购买
私有云桌面
云主机哪个好
域名怎么备案
手机云电脑
SSL证书申请
云点播服务器
免费OCR是什么
电脑云桌面
域名备案怎么弄
语音转文字
文字图片识别
云桌面是什么
网址安全检测
网站建设搭建
国外CDN加速
SSL免费证书申请
短信批量发送
图片OCR识别
云数据库MySQL
个人域名购买
录音转文字
扫描图片识别文字
OCR图片识别
行驶证识别
虚拟电话号码
电话呼叫中心软件
怎么制作一个网站
Email注册网站
华为VNC
图像文字识别
企业网站制作
个人网站搭建
华为云计算
免费租用云托管
云桌面云服务器
ocr文字识别免费版
HTTPS证书申请
图片文字识别转换
国外域名注册商
使用免费虚拟主机
云电脑主机多少钱
鲲鹏云手机
短信验证码平台
OCR图片文字识别
SSL证书是什么
申请企业邮箱步骤
免费的企业用邮箱
云免流搭建教程
域名价格