免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Rerun 中 ClassDescriptionMapElem 详解:AnnotationContext 语义类映射的编码原理与实战

Rerun 中 ClassDescriptionMapElem 详解:AnnotationContext 语义类映射的编码原理与实战 Rerun 中 ClassDescriptionMapElem 详解AnnotationContext 语义类映射的编码原理与实战【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun导读ClassDescriptionMapElem是 Rerun用于可视化、查询与流式处理多模态机器人数据的开源项目中一个编码层encodings辅助类型负责把语义类别 IDClassId映射到对应的类别描述ClassDescription是AnnotationContext标注上下文组件的内部键值对元素。本文将围绕该类型从字段语义、Arrow 内存布局、与周边类型ClassDescription/AnnotationInfo/ClassId的嵌套关系到 Python / Rust / C 三种 SDK 的实战用法逐层展开帮助你理解 Rerun 是如何在分割、关键点与骨架连线场景中完成类别 ID → 名称与颜色的解析。类型定位AnnotationContext 内部的键值对在 class_description_map_elem.md 中ClassDescriptionMapElem被明确定义为一个用于将encodings.ClassId映射到类别描述的辅助类型内部使用于components.AnnotationContext。这意味着你通常不会直接以独立组件的形式向数据流中写入它而是把它作为AnnotationContext的列表元素批量提交。对应的 Rust 组件定义位于 annotation_context.rs可以看到AnnotationContext的字段就是一个VecClassDescriptionMapElempub struct AnnotationContext( /// List of class descriptions, mapping class indices to class names, colors etc. pub Veccrate::encodings::ClassDescriptionMapElem, );即一个标注上下文 若干条 类别 ID → 类别描述 的映射记录每条记录就是一个ClassDescriptionMapElem。类型层面的约束定义在类型定义源文件 annotation_context.def.rs 中pub struct AnnotationContext { pub class_map: Vecrerun::encodings::ClassDescriptionMapElem, }字段语义键与值ClassDescriptionMapElem只有两个字段语义上构成典型的键值对字段类型含义class_id非空ClassId键一个 16 位语义类别 ID即components.ClassIdclass_description非空ClassDescription值该类别的名称、颜色等全部描述信息其中class_id在 class_id.md 中被定义为一个16 位UInt16的语义类别 ID。它本身只是一个数字标识真正承载这个 ID 显示成什么文字、什么颜色的是class_description这个值。从 Rust 的自动生成实现 class_description_map_elem.rs 可以看到完全一致的结构pub struct ClassDescriptionMapElem { /// The key: the components::ClassId. pub class_id: crate::encodings::ClassId, /// The value: class name, color, etc. pub class_description: crate::encodings::ClassDescription, }Arrow 内存布局完整嵌套的 Struct作为 Rerun 数据模型的一等公民ClassDescriptionMapElem通过 Arrow 格式序列化。其完整布局来自 class_description_map_elem.md如下Struct( class_id: non-null UInt16 class_description: non-null Struct( info: non-null Struct( id: non-null UInt16 label: Utf8 color: UInt32 ) keypoint_annotations: non-null List(non-null Struct( id: non-null UInt16 label: Utf8 color: UInt32 )) keypoint_connections: non-null List(non-null Struct( keypoint0: non-null UInt16 keypoint1: non-null UInt16 )) ) )这个布局可以从实现层面得到验证Rust 代码中的arrow_data_type()与to_arrow_opt会生成一个包含class_idUInt16和class_description嵌套Struct两个非空字段的StructArray序列化细节参见 class_description_map_elem.rs反序列化时同样按字段名从StructArray中取出class_id与class_description并强制非空class_description_map_elem.rs。理解这个布局的关键点顶层是 Struct键与值被绑定为一条不可分割的记录class_id是非空 UInt16任何映射都必须有明确键不允许缺失class_description是非空 Struct其内部又分为类别信息info、关键点标注列表keypoint_annotations与关键点连线列表keypoint_connections三个子字段连线是一对 UInt16keypoint0/keypoint1各指一个关键点 ID。值对象拆解ClassDescription 与 AnnotationInfo要真正用好ClassDescriptionMapElem需要理解其值一侧的两个下层类型。ClassDescription一个语义类的完整描述class_description.md 将ClassDescription定义为一个语义类的描述info非空AnnotationInfo类别自身的标注信息负责派生标签与颜色keypoint_annotations非空AnnotationInfo列表该类别下所有关键点的标注信息keypoint_connections非空KeypointPair列表关键点之间的连线骨架边。其工作方式是当一个实体被ClassId标注后Rerun 使用该类别对应的AnnotationInfo派生标签与颜色类内的关键点则用KeypointId标注并优先使用关键点自身关联的AnnotationInfo的标签与颜色。若某条keypoint_connections中定义了两点间的连线且这两个关键点都存在于该类别的实例中则两点之间绘制一条边边的标签与颜色同样取自该类别的AnnotationInfo。AnnotationInfoID、标签与颜色三元组annotation_info.md 定义了AnnotationInfo的三个字段字段类型含义id非空UInt16该标注所属的ClassId或KeypointIdlabelUtf8可空在 UI 中显示的标签colorRgba32UInt32可空应用到被标注实体上的颜色可见ClassDescriptionMapElem的 Arrow 布局其实就是把这套三元组id/label/color在info与keypoint_annotations两处复用。使用场景AnnotationContext 的查找语义ClassDescriptionMapElem并不孤立存在它服务的是 AnnotationContext 组件 的显示语义实体通过ClassId与KeypointId表达我属于哪个语义类别标签与颜色在适当的标注上下文中查找查找时沿着实体的路径层级向上遍历祖先取遇到的第一个标注上下文。也就是说把AnnotationContext挂在某个实体路径如masks、detections上会作用于该路径下所有子孙实体。该行为在 annotation_context.py 与类型定义源 annotation_context.def.rs 中有明确说明。archetype 层面的 annotation_context.md 还指出其可在 Spatial2DView、Spatial3DView 与 DataframeView 中展示。三语言实战如何构造 ClassDescriptionMapElem下面三个示例来自 docs/snippets/all/tutorials 的同一教程三种语言实现相同逻辑完整演示了从AnnotationInfo/ClassDescription构造映射的两种典型路径。Python直接把 AnnotationInfo / ClassDescription 交给 AnnotationContext在 annotation_context.py 中import rerun as rr rr.init(rerun_example_annotation_context_connections) # 两个类别一个纯标签一个带颜色 rr.log( masks, # 作用于 masks 之下的所有实体 rr.AnnotationContext( [ rr.AnnotationInfo(id0, labelBackground), rr.AnnotationInfo(id1, labelPerson, color(255, 0, 0)), ], ), staticTrue, ) # 带关键点与骨架连线的类别 rr.log( detections, # 作用于 detections 之下的所有实体 rr.ClassDescription( inforr.AnnotationInfo(0, labelSnake), keypoint_annotations[ rr.AnnotationInfo(idi, color(0, 28 * i, 0)) for i in range(10) ], keypoint_connections[(i, i 1) for i in range(9)], ), staticTrue, )Python 端之所以能这样直接传AnnotationInfo或ClassDescription是因为转换器会自动补全ClassDescriptionMapElem若传入的是AnnotationInfo则先包装成ClassDescription再取class_description.info.id作为class_id生成映射元素具体逻辑见 class_description_map_elem_ext.py。序列化时转换器把每个元素拆回ClassIdBatch与ClassDescriptionBatch两个 Arrow 数组再合并成StructArrayclass_description_map_elem_ext.py。Rust显式使用 ClassDescriptionMapElem::from在 annotation_context.rs 中映射元素通过元组或结构体字面量构造use rerun::{ AnnotationContext, AnnotationInfo, ClassDescription, Rgba32, encodings::{ClassDescriptionMapElem, KeypointId}, }; let rec rerun::RecordingStreamBuilder::new( rerun_example_annotation_context_connections, ).spawn()?; // 从 (id, label) 与 (id, label, color) 元组构造映射元素 rec.log_static( masks, // 作用于 masks 之下的所有实体 AnnotationContext::new([ ClassDescriptionMapElem::from((0, Background)), ClassDescriptionMapElem::from((1, Person, Rgba32::from_rgb(255, 0, 0))), ]), )?; // 显式构造 ClassDescription 后包装成映射元素 rec.log_static( detections, // 作用于 detections 之下的所有实体 AnnotationContext::new([ClassDescription { info: (0, Snake).into(), keypoint_annotations: (0..10) .map(|i| AnnotationInfo { id: i, label: None, color: Some(Rgba32::from_rgb(0, (28 * i) as u8, 0)), }) .collect(), keypoint_connections: (0..9) .map(|i| (KeypointId(i), KeypointId(i 1))) .map(Into::into) .collect(), }]), )?;这些From转换由 SDK 扩展实现提供(u16, str)、(u16, str, Rgba32)、AnnotationInfo与ClassDescription都可以直接转换成ClassDescriptionMapElem其中从ClassDescription转换时自动取info.id作为class_id见 class_description_map_elem_ext.rs。C通过容器构造在 annotation_context.cpp 中#include rerun.hpp int main(int argc, char* argv[]) { const auto rec rerun::RecordingStream(rerun_example_annotation_context_connections); rec.spawn().exit_on_failure(); // 两个类别一个纯标签一个带颜色 rec.log_static( masks, // 作用于 masks 之下的所有实体 rerun::AnnotationContext({ rerun::AnnotationInfo(0, Background), rerun::AnnotationInfo(1, Person, rerun::Rgba32(255, 0, 0)), }) ); // 关键点 骨架连线 std::vectorrerun::AnnotationInfo keypoint_annotations; for (uint16_t i 0; i 10; i) { keypoint_annotations.push_back(rerun::AnnotationInfo( i, rerun::Rgba32(0, static_castuint8_t(28 * i), 0) )); } std::vectorrerun::KeypointPair keypoint_connections; for (uint16_t i 0; i 9; i) { keypoint_connections.push_back(rerun::KeypointPair(i, i 1)); } rec.log_static( detections, // 作用于 detections 之下的所有实体 rerun::AnnotationContext({rerun::ClassDescription( rerun::AnnotationInfo(0, Snake), keypoint_annotations, keypoint_connections )}) ); }注意三处示例都使用了staticTruePython或log_staticRust / C标注上下文通常是在数据录制开始时一次性定义的静态元数据无需随时间变化。从定义到绑定的生成链ClassDescriptionMapElem这类类型并非手工维护而是由 Rerun 的类型构建器自动生成。以 Rust 为例生成的代码头部标注了来源// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs // Based on crates/build/re_type_definitions/rerun/encodings/class_description_map_elem.def.rs.也就是说类型语义的唯一事实来源是crates/build/re_type_definitions下的定义文件构建器据此生成 Rust、Python、C 三种语言绑定Rust 绑定在 class_description_map_elem.rs 与其_ext扩展文件Python 绑定在 rerun_py/rerun_sdk/rerun 下的 encodings 与 components 目录。这也是编码层类型 组件层类型这一分层设计的由来ClassDescriptionMapElem、ClassDescription、AnnotationInfo归属encodings纯编码结构而AnnotationContext归属components可落盘组件后者通过VecClassDescriptionMapElem复用前者。稳定性与使用注意事项标记为 unstableClassDescriptionMapElem在文档与源码中均带有⚠️ This type is _unstable_ and may change significantly in a way that the data wont be backwards compatible.警告且状态标注为#[rerun(state unstable)]见 annotation_context.def.rs。这意味着该类型在后续版本中可能以不向后兼容的方式变化涉及数据落盘与长期归档时需关注版本对应关系。不直接独立使用它是AnnotationContext的内部实现细节。日常开发中优先通过rr.AnnotationContext(...)/AnnotationContext::new(...)高阶 API 构造转换器会自动补齐class_id。查找语义依赖路径层级标注上下文沿实体路径向上查找第一个匹配项因此把上下文挂在越靠近根的位置影响范围越大挂得越深越能覆盖局部子树的显示规则。总结ClassDescriptionMapElem是 Rerun 标注体系中最小的映射单元一条记录绑定一个 16 位ClassId与其完整的ClassDescription类别信息 关键点标注 骨架连线多个映射元素聚合成AnnotationContext再通过路径层级查找为分割掩码、检测框和关键点骨架提供标签与颜色。理解它的字段语义、Arrow 嵌套布局与三语言构造方式即可在机器人视觉数据可视化中高效地定制语义标注显示规则。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表