Rerun 组件 ValueRange 详解:深度/张量/体素数据的数值范围定义与底层实现
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
导读
ValueRange是 Rerun 数据模型(re_sdk_types)中一个用于声明数据"期望或合法取值区间"的组件类型:它由一个浮点下界和一个浮点上界构成,在深度图、张量、体素网格等场景中扮演着数据范围标注与可视化映射依据的角色。本文以 docs/content/reference/types/components/value_range.md 为主线,结合仓库中的类型定义、Rust 生成代码、扩展实现与可视化面板源码,完整讲解其语义、Arrow 编码、跨语言 API 形态、使用方式与底层存储细节,帮助你理解并正确使用这一组件。
⚠️稳定性提示:
ValueRange当前处于unstable状态,后续可能发生不保证向后兼容的显著变更。在生产数据管道中引用该类型时,请留意 Rerun 的版本更新与变更日志。
一、组件语义:它到底描述什么
Rerun 的类型体系将"语义组件(component)"与"数据结构(datatype)"严格分层:组件表达业务语义,而结构只负责承载原始数据。ValueRange属于前者,其官方定义非常精炼:
Range of expected or valid values, specifying a lower and upper bound. (期望值或合法值区间,指定一个下界与上界。)
这意味着该组件并不包含数据本体,而是对同一实体(entity)上其他数据的取值约束声明。从类型定义源码 crates/build/re_type_definitions/rerun/components/value_range.def.rs 可以看到它的声明方式:
/// Range of expected or valid values, specifying a lower and upper bound. #[rerun::rerun_type] #[rerun(state = "unstable")] #[rust(derive(Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable))] #[rust(repr = "transparent")] pub struct ValueRange { pub range: rerun::encodings::Range1D, }三个关键信息:
- 结构体内只有单一字段
range,类型是内建的Range1D编码(encoding); state = "unstable"是文档页开头"不稳定"警告的直接来源;repr = "transparent"说明它仅仅是Range1D的一层薄封装,运行期没有额外开销。
Rerun 使用这些.def.rs类型定义文件(位于 crates/build/re_type_definitions/rerun/components/),通过re_types_builder代码生成器统一产出 Rust、Python、C++ 三套语言绑定——这正是文档页底部三个语言 API 链接的由来。文档页顶部"DO NOT EDIT"注释也表明,该 Markdown 是由 crates/build/re_types_builder/src/codegen/docs/website.rs 自动生成的类型参考页。
二、Rerun 编码:Range1D 与它的实现
ValueRange的底层编码为Range1D,其定义在 docs/content/reference/types/encodings/range1d.md:一个一维区间,同样由下界与上界组成。
对应到 Rust 实现 crates/store/re_sdk_types/src/encodings/range1d.rs,Range1D是一个包含两个f64的透明元组结构体:
#[repr(C)] pub struct Range1D(pub [f64; 2usize]);下标 0 为下界(start),下标 1 为上界(end)。因为ValueRange对Range1D实现了Deref/DerefMut(见下文),所以通过ValueRange实例可以直接按索引访问这两个值。
Range1D同时也是其他区间类类型的共享基础编码——从 docs/content/reference/types/encodings/range1d.md 的 "Used by" 列表可知,除ValueRange外,Range1D组件与Range2D编码也复用了同一套区间概念,体现 Rerun 中"编码可被多个组件复用"的设计。
三、Arrow 数据格式:FixedSizeList(2 x non-null Float64)
ValueRange的官方文档给出其 Arrow 数据格式为:
FixedSizeList(2 x non-null Float64)这一格式由Range1D的序列化实现直接决定。在 crates/store/re_sdk_types/src/encodings/range1d.rs 中可以看到 Arrow 类型声明:
fn arrow_data_type() -> arrow::datatypes::DataType { use arrow::datatypes::*; DataType::FixedSizeList( std::sync::Arc::new(Field::new("item", DataType::Float64, false)), 2, ) }逐项解读:
| 记号 | 含义 | 对应实现 |
|---|---|---|
FixedSizeList | 定长列表,每个元素恰好包含 2 个子项 | DataType::FixedSizeList(_, 2) |
2 | 列表长度恒为 2(下界、上界各一) | 构造参数2 |
non-null Float64 | 每个子项都是非空的 64 位浮点数 | Field::new("item", DataType::Float64, false),false即不允许 null |
序列化路径(ToArrow)会将Range1D([start, end])展平为连续的两个f64,打包进FixedSizeListArray;反序列化路径(FromArrow)则按相同布局还原(见同一文件的impl FromArrow)。选择FixedSizeList而非变长List的原因也很直接:区间结构长度恒定,定长布局在内存中紧凑连续、便于 SIMD 与随机访问,也避免了每行存储长度前缀的开销。由于子项与列表本身均声明为非空,一个合法的ValueRange不会出现"只给了下界"或"包含 null"的半残状态。
四、跨语言 API:ValueRange 在不同 SDK 中的形态
Rerun 从同一份类型定义生成多语言绑定,ValueRange在三种官方 SDK 中均有对应入口:
- 🌊C++:
rerun::components::ValueRange(见 C++ API 参考) - 🐍Python:
rerun.components.ValueRange(见 Python API 参考) - 🦀Rust:
rerun::components::ValueRange(见 docs.rs 文档)
4.1 Rust 侧:透明封装与便捷构造
生成的组件代码位于 crates/store/re_sdk_types/src/components/value_range.rs,核心是一个repr(transparent)的包装类型:
pub struct ValueRange(pub crate::encodings::Range1D);并实现了:
WrapperComponent:组件注册名为"rerun.components.ValueRange"(第 40-42 行),编码类型为Range1D;From<T: Into<Range1D>>:任何能转成Range1D的值(如[f64; 2])都能直接into()成ValueRange;Deref/DerefMut:可直接以Range1D的视角操作;Borrow<Range1D>、Clone、Copy、PartialEq,以及bytemuck::Pod/Zeroable(内存零拷贝、可直接按字节解释)等底层 trait。
真正面向使用者的构造与访问方法定义在扩展文件 crates/store/re_sdk_types/src/components/value_range_ext.rs 中(Rerun 将"手写逻辑"与"生成代码"分离的典型模式):
impl ValueRange { pub fn new(start: f64, end: f64) -> Self; // 构造 [start, end] pub fn start(&self) -> f64; // 下界 pub fn end(&self) -> f64; // 上界 pub fn start_mut(&mut self) -> &mut f64; // 可变下界 pub fn end_mut(&mut self) -> &mut f64; // 可变上界 }其Display输出格式为[start, end],例如[0.0, 1.0]。值得注意的默认值实现:
impl Default for ValueRange { fn default() -> Self { Self::new(0.0, 1.0) } }即未显式指定时,默认区间为[0.0, 1.0]。
4.2 Python 侧:列表字面量直接传入
在 Python SDK 中,ValueRange通常无需手动构造,直接传[start, end]形式的双元素列表即可被自动转换。以体素网格示例 docs/snippets/all/archetypes/voxel_grid_map_simple.py 为例:
voxel_grid_map = rr.archetypes.VoxelGridMap( ..., value_range=[0.0, 1.0], )同主题的 C++(voxel_grid_map_simple.cpp)与 Rust(voxel_grid_map_simple.rs)示例位于 docs/snippets/all/archetypes/ 下,可对照三种语言的使用差异。
4.3 C++ 侧
C++ 绑定由相同定义生成,结构与 Rust 一致:rerun::components::ValueRange内部持有rerun::encodings::Range1D,同样提供区间构造与访问接口。
五、使用场景:哪些 Archetype 用到了 ValueRange
根据文档页 "Used by" 列表,ValueRange被以下五种 archetype 作为可选字段使用:
| Archetype | 字段名 | 语义 | 对应定义文件 |
|---|---|---|---|
DepthImage | depth_range | 深度值的显示/有效范围 | depth_image.def.rs |
EncodedDepthImage | depth_range | 编码深度流的深度范围 | encoded_depth_image.def.rs |
Tensor | value_range | 张量元素的数值范围 | tensor.def.rs |
Volume3D | value_range | 体数据的取值窗口 | volume_3d.def.rs |
VoxelGridMap | value_range | 体素场数值的显示范围 | voxel_grid_map.def.rs |
5.1 典型例子:DepthImage
以 docs/content/reference/types/archetypes/depth_image.md 为例,DepthImage的可选字段包括:
buffer(必填,ImageBuffer)format(必填,ImageFormat)meter(DepthMeter,深度单位换算)colormap(Colormap)depth_range(ValueRange)← 本文主题point_fill_ratio、draw_order、magnification_filter
深度图由深度相机采集,每个像素是一个"按DepthMeter单位解释的深度值"。depth_range在此处用于声明深度值的期望区间,可视化端据此决定色彩映射等处理所覆盖的数值窗口。
5.2 可视化端如何消费它
ValueRange不是被"存储"后就闲置的元数据,查看器端会主动读取它。例如:
- 张量视图在构建可视化器时读取该组件(见 crates/views/re_view_tensor/src/visualizer_system.rs);
- 体素网格与编码深度视频的可视化器同样引用它(见 crates/views/re_view_spatial/src/visualizers/voxel_grid_map.rs 与 crates/views/re_view_spatial/src/visualizers/video/encoded_depth_image.rs);
- 组件 UI 层为它注册了专门的区间编辑器
edit_view_range1d(见 crates/viewer_support/re_component_ui/src/lib.rs),用户在查看器中可直接以区间控件形式查看和编辑该值; - 当组件缺失时,由 fallback 逻辑补上默认值(见 crates/viewer_support/re_component_fallbacks/src/component_fallbacks.rs),与 Rust 侧
Default的[0.0, 1.0]保持一致。
六、在日志 API 中的实际用法
实际开发中最常见的用法是:不直接 log 这个组件,而是通过 archetype 的命名参数/字段顺带写入。以 Python 为例:
import rerun as rr # 深度图:通过 depth_range 传入期望区间 rr.log( "world/camera/depth", rr.DepthImage( data=z_vals, # 深度数据 meter=0.001, # 每单位对应毫米 depth_range=[0.0, 10.0], # ValueRange:[下界, 上界] ), ) # 张量:通过 value_range 指定数值窗口 rr.log("sensor/tensor", rr.Tensor(data=tensor_data, value_range=[-1.0, 1.0])) # 体素网格:同样使用 value_range rr.log( "map/voxels", rr.VoxelGridMap(grid=..., value_range=[0.0, 1.0]), )从 Rust 实现(value_range_ext.rs)可知,传入的列表会被严格映射为二元组[start, end],并在序列化时以两个非空f64写入FixedSizeList(2)。因此:
- 列表必须恰好包含两个数值(下界、上界);
- 数值类型应为浮点(整型会在语言层转换,但底层始终以
Float64存储); - 空区间(下界 == 上界)或"上下界颠倒"在类型层面不会被拒绝——该组件只声明区间,语义校验由具体可视化逻辑负责。
七、与其他区间类型的区别
Rerun 的类型体系中存在一组容易混淆的"区间"类型,建议按用途区分:
| 类型 | 层级 | 含义 |
|---|---|---|
ValueRange(本文) | 组件 | 数据的期望/合法取值范围,供张量、深度、体素等可视化使用 |
Range1D | 编码(datatype) | 一维区间[start, end]的纯数据结构,被ValueRange等复用 |
Range2D | 编码 | 二维区间,同样以Range1D为基础扩展(见 range1d.md 的 Used by) |
简言之:ValueRange是"带语义的组件",Range1D是"无语义的容器"。前者负责告诉查看器"数据应该在哪个窗口内解释",后者只负责把两个浮点数组织成 Arrow 定长列表。
八、小结
ValueRange是 Rerun 数据类型体系中的一个基础组件:
- 语义:声明数据的期望/合法区间,当前标记为 unstable;
- 编码:包装
Range1D([f64; 2]),Arrow 存储为FixedSizeList(2 x non-null Float64); - 使用:无需单独构造,通常通过
DepthImage.depth_range、Tensor.value_range、Volume3D.value_range、VoxelGridMap.value_range等 archetype 可选字段以[start, end]形式传入; - 默认值:
[0.0, 1.0](RustDefault与组件 fallback 一致); - 消费方:张量视图、体素网格/编码深度可视化器、组件 UI 区间编辑器(re_component_ui/src/lib.rs)。
掌握这个组件,是正确控制深度图、张量与体素数据的数值窗口、让可视化结果贴合真实物理量纲的第一步。由于它仍处于 unstable 状态,升级 Rerun 版本时请关注 CHANGELOG.md 中对类型系统的变更记录。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考