Rerun 颜色编码 Rgba32 全面解析:sRGB 色彩空间、位布局与三语言 API 实战
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
Rgba32 是 Rerun 数据模型中最核心的颜色编码类型,承载了Color、AlbedoFactor、AnnotationInfo等组件与所有 2D/3D 可视化场景的颜色数据。本文以官方类型参考文档为主体,结合仓库内 Rust、Python、C++ 三套 SDK 的源码实现,完整解读 Rgba32 的语义约定、32 位内存布局、Arrow 序列化方式,并给出可直接落地的构造、转换与批量使用代码示例。
Rgba32 的类型语义:未预乘 alpha、sRGB gamma、线性 alpha
根据官方参考文档 rgba32.md 的定义,Rgba32 是:
An RGBA color with unmultiplied/separate alpha, in sRGB gamma space with linear alpha.
即一个alpha 未预乘(unmultiplied/separate)的 RGBA 颜色,RGB 通道处于sRGB gamma 空间,而 alpha 通道是线性空间的。三个关键语义点需要特别注意:
- 未预乘 alpha:颜色值没有被 alpha 通道预先乘过。
(r, g, b, a) = (255, 0, 0, 128)表示"半透明的纯红",而不是"红值减半后的暗红"。这保证了颜色在透明度变化时色相不会漂移,也便于在渲染管线中做正确的 alpha 合成。 - sRGB gamma 空间:R/G/B 分量是经 gamma 编码的 8 位数值(0–255),与屏幕上直接显示的颜色一致。渲染时如果需要做光照等线性运算,需要先用 sRGB 传递函数解码为线性值。
- 线性 alpha:alpha 分量直接以线性 0–255 表示,不经过 gamma 编码。
这套约定与 ecolor(egui 的颜色库)的Color32::from_rgba_unmultiplied完全一致,方便在 UI 层直接互转(详见下文 Rust API 一节)。
32 位内存布局:最高字节为 R,最低字节为 A
文档明确规定了 Rgba32 的存储方式:
The color is stored as a 32-bit integer, where the most significant byte is
Rand the least significant byte isA.
一个Rgba32底层就是一个u32,从最高位到最低位依次是 R、G、B、A 四个字节:
31 23 15 7 0 ┌─────────────────────┬─────────────────────┬─────────────────────┬─────────────────┐ │ R │ G │ B │ A │ └─────────────────────┴─────────────────────┴─────────────────────┴─────────────────┘ 0xRRGGBBAA例如纯红色不透明(255, 0, 0, 255)打包为0xFF0000FF。这一点在仓库的各语言实现中高度一致:
- Rust 扩展实现 rgba32_ext.rs 中,
from_unmultiplied_rgba通过(r << 24) | (g << 16) | (b << 8) | a完成打包; - C++ 头文件 rgba32.hpp 的构造函数与
r()/g()/b()/a()访问器同样按rgba >> 24 & 0xFF等位移方式取字节; - Python 端 _color_conversion.py 的
u8_array_to_rgba通过把数组逆序为[a, b, g, r]再以uint32重新解释内存,得到0xRRGGBBAA打包值。
Arrow 数据类型:以 UInt32 传输与存储
作为 Rerun 类型系统的一部分,Rgba32 在 Arrow 层面对应原生的UInt32类型(见文档 "Arrow datatype" 一节)。这意味着在日志记录、RRD 文件存储和跨语言数据交换中,一个 Rgba32 颜色就是一个 4 字节无符号整数,不存在结构体或嵌套的开销。
在 Rust 生成代码 rgba32.rs 中可以清晰地看到这条链路:
ArrowDataType::arrow_data_type()返回DataType::UInt32;ToArrow::to_arrow将Rgba32解包为u32,构建PrimitiveArray<UInt32Type>写入 Arrow 数组;FromArrow::from_arrow反向把UInt32Array的每个元素重新包装为Rgba32,并通过err_on_nulls拒绝空值。
该类型的 loggable 名称是rerun.encodings.Rgba32,例如 C++ 中Loggable 的 ComponentType 常量即声明为"rerun.encodings.Rgba32",并以arrow::UInt32Builder完成 Arrow 构建。
单一事实来源:.def.rs 类型定义与代码生成
Rerun 的所有 SDK 类型都并非手写三份,而是由一份声明式定义统一生成。Rgba32 的权威定义位于 rgba32.def.rs,其中标注了:
#[rerun::rerun_type] #[arrow(transparent)] // Arrow 层透明展开为底层 u32 #[python(aliases = "int | Sequence[int | float] | npt.NDArray[np.uint8 | np.float32 | np.float64]")] #[rust(repr = "transparent")] #[rerun(state = "stable")] // 稳定 API,不会破坏性变更 pub struct Rgba32 { pub rgba: u32, }#[arrow(transparent)]决定了其 Arrow 表示为裸UInt32;#[rerun(state = "stable")]表明该类型已进入稳定状态,可作为长期兼容的公共 API 使用。re_types_builder据此生成 Rust、Python、C++ 三套绑定,各语言文件头部都有 "DO NOT EDIT! This file was auto-generated" 注释可验证(如 rgba32.rs、rgba32.hpp)。
Rust API:构造、转换与常量
Rust 侧通过扩展文件 rgba32_ext.rs 提供了完整的实用方法,生成的结构体本身是#[repr(transparent)]的pub struct Rgba32(pub u32)(见 rgba32.rs),并派生了Copy、PartialEq、Ord、Hash、bytemuck::Pod等 trait。
构造方法
| 方法 | 说明 | 示例 |
|---|---|---|
from_rgb(r, g, b) | 由 sRGB gamma 空间的 0–255 三通道构造,alpha 自动置 255 | Rgba32::from_rgb(255, 0, 0) |
from_unmultiplied_rgba(r, g, b, a) | 由未预乘的四通道构造 | Rgba32::from_unmultiplied_rgba(255, 0, 0, 128) |
from_u32(rgba) | 直接由打包好的0xRRGGBBAA构造 | Rgba32::from_u32(0xFF0000FF) |
from_linear_unmultiplied_rgba_f32(r, g, b, a) | 由 0–1 线性空间 sRGB 值构造(有损转换,需ecolorfeature) | Rgba32::from_linear_unmultiplied_rgba_f32(1.0, 0.0, 0.0, 1.0) |
反向转换
to_array(self) -> [u8; 4]:返回[r, g, b, a]字节数组;to_u32(self) -> u32:返回打包后的0xRRGGBBAA整数。
预定义常量
Rgba32::BLACK:from_rgb(0, 0, 0);Rgba32::WHITE:from_rgb(255, 255, 255);Rgba32::TRANSPARENT:from_unmultiplied_rgba(0, 0, 0, 0),即完全透明。
From 转换支持
Rgba32实现了丰富的From转换,几乎任何颜色形态都可以无缝流入:
From<(u8, u8, u8)>、From<(u8, u8, u8, u8)>:元组直接构造;From<[u8; 3]>、From<[u8; 4]>:数组直接构造;From<u32>/From<Rgba32> for u32:与打包整数互转;ecolorfeature 下与ecolor::Color32、ecolor::Rgba双向互转,UI 层取色、颜色拾取器可直接复用。
组件包装:Color
Rgba32 最常见的载体是Color组件。组件定义 color.def.rs 中pub rgba: rerun::encodings::Rgba32直接内嵌该编码,其扩展实现 color_ext.rs 提供了同名便捷 API(Color::from_rgb、Color::from_u32、Color::new(impl Into<Rgba32>)等)。值得注意的是Color::default()返回WHITE,注释中给出的理由(见 color_ext.rs)是:白色作为乘法因子不改变任何颜色,且在多数场景下比黑色更可见。
Python API:灵活的多形态输入与自动类型推断
Python 端在 rgba32_ext.py 中实现了非常宽容的输入解析,官方类型别名(见 rgba32.def.rs)为:
int | Sequence[int | float] | npt.NDArray[np.uint8 | np.float32 | np.float64]Rgba32接受三种形态的输入:
- 打包整数:
int或可转为 int 的对象,直接视为0xRRGGBBAA打包值; - 0–255 的序列:长度 3 或 4 的
Sequence[int]或np.uint8数组,按[r, g, b, (a)]解释; - 0–1 的浮点数组:
np.float32/np.float64数组,会被乘以 255 并四舍五入到 0–255 的 sRGB 空间(浮点颜色约定见 rgba32.def.rs)。
Rgba32Batch则进一步接受 Nx3 或 Nx4 的批量数组、Rgba32实例序列以及异构序列(整数、子序列混合)。核心转换逻辑rgba__field_converter_override与native_to_pa_array_override会按上述规则依次尝试推断:
rr.Rgba32(255, 0, 0) # (255,0,0) → 0xFF0000FF rr.Rgba32([255, 0, 0, 128]) # 未预乘 RGBA rr.Rgba32(0xFF0000FF) # 直接打包值 rr.Rgba32(np.array([1.0, 0.0, 0.0])) # 0-1 浮点,乘 255 取整浮点到 gamma 的转换曲线
当输入为 0–1 浮点时,linear_to_gamma_u8_value 实现了标准的 sRGB 传递函数,与 Rust 参考实现逐行对应:
if l <= 0.0031308: round(3294.6 * l) # 线性段 else: round(269.025 * l^(1/2.4) - 14.025) # 幂律段对于 RGBA 浮点像素,linear_to_gamma_u8_pixel 仅对 RGB 三个通道做 gamma 编码,alpha 通道保持线性(np.around(255 * alpha)),这与"RGB 处于 sRGB gamma、alpha 处于线性空间"的类型语义完全吻合。
歧义输入告警
Python 实现还内置了歧义防护:当传入长度 3 或 4 的数组但值不全小于 256 时,会发出RerunWarning,提示用户如果本意是0xRRGGBBAA打包值,应显式以np.uint32类型包裹(见 rgba32_ext.py)。
C++ API:构造与分量访问
C++ 端 rgba32.hpp 提供struct Rgba32 { uint32_t rgba; }及以下便捷接口:
rerun::encodings::Rgba32 c1(255, 0, 0); // (r, g, b),alpha 默认 255 rerun::encodings::Rgba32 c2(255, 0, 0, 128); // (r, g, b, a) 未预乘 rerun::encodings::Rgba32 c3(uint8_t[4]{...}); // 数组构造 rerun::encodings::Rgba32 c4(0xFF0000FFu); // 直接打包值 uint8_t r = c1.r(); // 0xFF uint8_t g = c1.g(); // 0x00 uint8_t b = c1.b(); // 0x00 uint8_t a = c1.a(); // 0xFFr()/g()/b()/a()访问器分别通过(rgba >> 24) & 0xFF、(rgba >> 16) & 0xFF、(rgba >> 8) & 0xFF、rgba & 0xFF解包分量,与位布局约定一一对应。
使用场景:Color、AlbedoFactor、AnnotationInfo 与语义分割
文档 "Used by" 一节列出了三个直接使用 Rgba32 的类型:
Color:最通用的颜色组件,被Points2D/Points3D、Boxes2D/Boxes3D、LineStrips2D/LineStrips3D、Arrows2D/Arrows3D、Mesh3D、GaussianSplats3D、SeriesLines、GraphNodes、GeoPoints等 20 余个 Archetype 使用,覆盖几乎所有可视化实体;AlbedoFactor:整实体级别的颜色乘数,通常用于Asset3D、Mesh3D的材质反照率调节。注意它承载的是"乘数"语义,因此默认值选白色(乘法中性元)最为安全;AnnotationInfo:标注类别的颜色与标签,其定义 annotation_info.def.rs 中pub color: Option<rerun::encodings::Rgba32>以可选字段形式引用 Rgba32。
一个典型的端到端场景是语义分割可视化。在 segmentation_image.rs 的内嵌示例中,每个像素是ClassId,颜色由AnnotationContext映射而来:
let annotation = rerun::AnnotationContext::new([ (1, "red", rerun::Rgba32::from_rgb(255, 0, 0)), (2, "green", rerun::Rgba32::from_rgb(0, 255, 0)), ]); rec.log_static("/", &annotation)?; rec.log("/image", &rerun::SegmentationImage::from_image(image)?)?;此处Rgba32::from_rgb直接为类别提供标注颜色,观感与数据分离——标签颜色可以随时调整而无需重写图像数据。
实践要点小结
- 始终使用未预乘 alpha:传入四通道颜色时,alpha 不要与 RGB 相乘,半透明渲染交给 Viewer 的合成管线处理;
- 区分 gamma 与线性:RGB 通道按 0–255 的 sRGB gamma 值传入;只有在使用浮点(0–1)输入时才走 gamma 编码曲线,且 alpha 始终按线性解释;
- 打包值注意字节序:
0xRRGGBBAA中 R 在最高字节、A 在最低字节,与其他库(如 0xAABBGGRR 的 BGRA 打包)不同,混用时务必显式转换; - 批量性能:Python 批量传色优先使用
np.uint8的 Nx3/Nx4 数组或np.uint32打包数组,避免逐元素构造开销; - 默认值语义:
Color::default()与AlbedoFactor语义上的中性值是白色(0xFFFFFFFF),乘法运算不改变颜色,透明度场景才使用TRANSPARENT。
通过本文的文档 + 源码对照,你可以放心地在 Rust、Python、C++ 任一 SDK 中正确构造、转换和批量提交 Rgba32 颜色,并理解其在 Arrow 数据链路中的真实形态,从而避免常见的颜色空间与 alpha 语义陷阱。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考