Rerun 图像编码之 ColorModel:颜色分量模型与像素格式定义详解
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
ColorModel是 Rerun 数据模型(rerun.encodings.ColorModel)中用于描述图像颜色分量构成的核心枚举类型,它声明一幅图像里"到底有哪些颜色通道",并与ChannelDatatype(每个通道的数据类型)共同决定图像的像素格式。无论你是通过 Python、Rust 还是 C++ SDK 记录 RGB 相机帧、灰度深度图,还是 OpenCV 产出的 BGR 数据,都需要理解ColorModel的五个取值及其在ImageFormat中的组合规则。读完本文,你将掌握ColorModel每个变体的语义、数值编码、Arrow 序列化方式、与PixelFormat/ChannelDatatype的优先级关系,以及在 Rerun 中正确声明与转换图像格式的完整方法。
一、ColorModel 是什么
ColorModel的官方定义位于 color_model.md,其作用是:
Specifies what color components are present in an
archetypes.Image.(声明Image图元中存在的颜色分量。)
更关键的一句话是:
This combined with
encodings.ChannelDatatypedetermines the pixel format of an image.(它与ChannelDatatype共同决定图像的像素格式。)
也就是说,ColorModel回答的是"图像有哪几种颜色通道(以及通道顺序)",而ChannelDatatype回答的是"每个通道用什么数值类型存储(U8、F16……)"。两者缺一不可:仅有RGB无法确定一个像素占多少字节,仅有U8也无法知道一个像素由几个字节组成。
在 Rerun 的类型体系里,ColorModel属于Encoding(编码)层类型,被ImageFormat结构体引用(见 image_format.md 的 "Used by" 一节),而ImageFormat又是components.ImageFormat的载体,随archetypes.Image一起被记录、传输与渲染。
二、五个变体:语义与枚举值
ColorModel共定义了 5 个变体,每个变体对应一个固定的u8数值。下表汇总了官方文档与 color_model.rs 源码中的完整定义:
| 变体 | 数值 | 含义 | 通道数 | 是否含 Alpha |
|---|---|---|---|---|
L | 1 | 灰度亮度/强度/明度(Grayscale luminance intensity/brightness/value),有时称为Y | 1 | 否 |
RGB | 2 | 红、绿、蓝(Red, Green, Blue) | 3 | 否 |
RGBA | 3 | 红、绿、蓝、透明度(Red, Green, Blue, Alpha) | 4 | 是 |
BGR | 4 | 蓝、绿、红(Blue, Green, Red) | 3 | 否 |
BGRA | 5 | 蓝、绿、红、透明度(Blue, Green, Red, Alpha) | 4 | 是 |
几点值得注意:
L是默认变体。在 Rust 实现中L带有#[default]属性(color_model.rs 第 35 行),这意味着未显式指定颜色模型时,默认按单通道灰度处理。L即 Y。文档明确指出灰度分量"sometimes calledY",这与 YUV 色彩空间中的亮度分量 Y 概念一致,也呼应了PixelFormat中Y8_FullRange、Y8_LimitedRange等单色格式的命名(详见 pixel_format.md)。- BGR/BGRA 的存在是为了兼容 OpenCV 等以 BGR 为内存顺序的视觉库,避免在记录前手动翻转通道顺序。
通道数与 Alpha 的派生逻辑
Rust 侧通过扩展方法提供了两个派生属性(见 color_model_ext.rs):
num_channels():L返回 1,RGB | BGR返回 3,RGBA | BGRA返回 4;has_alpha():RGBA | BGRA返回true,其余返回false。
Python 侧在 color_model_ext.py 中提供了等价的num_channels()方法,逻辑与 Rust 完全一致,未知值会抛出ValueError。这两个派生属性在图像缓冲区的尺寸校验、as_pil_image转换等场景中被大量使用(见下文)。
三、Arrow 序列化:单个 UInt8 即可表达
ColorModel的 Arrow 数据类型被定义为UInt8(color_model.rs 第 57-63 行的arrow_data_type()实现):
UInt8由于枚举在 Rust 中以#[repr(u8)]布局,序列化时直接把*datum as u8写入PrimitiveArray<UInt8Type>;反序列化时则通过Enum::try_from_integer(val)将整数映射回变体,try_from_integer的实现是variants().get((value as usize).wrapping_sub(1)),即用值 - 1索引变体数组(值 1 对应第 0 个变体L,依次类推)。无法映射的整数会报missing_union_arm错误(color_model.rs 第 110-127 行)。
这意味着5 个颜色模型在数据层只占用每像素 1 字节(作为元数据时更是微乎其微),并且可以安全地与ChannelDatatype、PixelFormat一样用UInt8承载在 Arrow 记录中。Rust 端的Display实现(color_model.rs 第 133-143 行)会输出L、RGB、RGBA、BGR、BGRA这些字符串,方便日志与调试。
四、与 ChannelDatatype 组合:像素格式的两要素
ChannelDatatype(见 channel_datatype.md)定义每个颜色通道内部的数据编码,共 11 个变体:
| 类别 | 变体与数值 |
|---|---|
| 无符号整型 | U8=6、U16=8、U32=10、U64=12 |
| 有符号整型 | I8=7、I16=9、I32=11、I64=13 |
| 浮点型 | F16=33(半精度)、F32=34、F64=35(双精度) |
官方文档给出的组合示例是RGB+U8(红绿蓝各 8 位,即常见的 24 位真彩);同理:
L+U8→ 8 位灰度;L+U16→ 16 位深度/灰度图;RGB+F32→ 浮点 RGB(例如 HDR 或科学可视化数据);RGBA+U8→ 32 位带透明度图像。
两者合起来恰好回答"像素格式"的所有问题:ColorModel决定通道结构与顺序,ChannelDatatype决定每通道位宽与数值语义(是否带符号、是否浮点)。
五、ImageFormat:承载三者并定义优先级
ColorModel并非孤立使用,它最终会被装入ImageFormat结构体(Rust 实现见 image_format.rs),该结构体由五个字段组成:
| 字段 | 类型 | 说明 |
|---|---|---|
width | u32(非空) | 图像宽度(像素) |
height | u32(非空) | 图像高度(像素) |
pixel_format | PixelFormat(可空) | 主要用于色度下采样格式或每通道位数不一致的格式 |
color_model | ColorModel(可空) | L、RGB、RGBA……需配合channel_datatype才能完整描述像素格式 |
channel_datatype | ChannelDatatype(可空) | 每个通道的数据类型(U8、F16……) |
优先级规则(在 image_format.md 中有明确说明,也体现在pixel_format字段的 doc 注释中):
若指定了
pixel_format,则它优先于color_model与channel_datatype(后两者被忽略)。
也就是说,存在两条描述像素格式的路径:
- 常规路径:
color_model+channel_datatype,适用于绝大多数未压缩、无色度下采样的图像; - 特殊路径:
pixel_format,适用于 YUV 4:2:0 / 4:2:2 / 4:4:4 等色度下采样格式以及每通道位数不一致的格式(如NV12、YUY2、I420系列,共 10 个变体,详见 pixel_format.md)。
ImageFormat的 Arrow 表示为五字段Struct(width、height为UInt32,其余三个编码字段均为UInt8),与文档中的描述完全对应。
六、源码级验证:SDK 如何自动推断与校验 ColorModel
理解ColorModel的最佳方式之一是看 SDK 在记录图像时如何推断、校验并消费它。
Python 端的自动推断
在 image_ext.py 的Image构造逻辑中,当未显式传入color_model时,SDK 依据通道数自动推断:
if color_model is None: if channels == 1: color_model = ColorModel.L elif channels == 3: color_model = ColorModel.RGB elif channels == 4: color_model = ColorModel.RGBA else: _send_warning_or_raise(f"Expected 1, 3, or 4 channels; got {channels}")如果显式指定了color_model,则用channel_count_from_color_model校验实际通道数与模型要求的通道数(L→1、RGB/BGR→3、RGBA/BGRA→4)是否匹配,不匹配时给出告警或报错。随后ChannelDatatype由 NumPy dtype(from_np_dtype)自动推导,最终组装成ImageFormat(width, height, channel_datatype, color_model)并写入buffer。
单元测试佐证
test_image.py 中直接构造了"color_model": rr.encodings.ColorModel.RGB的测试用例,验证了 RGB 模型在记录-序列化-反序列化全链路上的正确性。
BGR/BGRA 的转换与压缩限制
由于as_pil_image假设 PIL 使用 L 或 RGB(A) 通道顺序,因此在 image_ext.py 的as_pil_image()中,对 BGR/BGRA 数据做了通道重排:
if image_format.color_model == ColorModel.BGR: image = image[:, :, ::-1] # BGR -> RGB elif image_format.color_model == ColorModel.BGRA: image = image[:, :, [2, 1, 0, 3]] # BGRA -> RGBA同时,compress()(JPEG 压缩)只接受L、RGB、BGR三种模型且通道数据类型必须为U8,遇到RGBA/BGRA会抛出 "Cannot JPEG compress an image of type …" 的错误——这再次体现了ColorModel在 SDK 各个功能点中的实际约束作用。
七、各语言 API 中的使用方式
ColorModel在三种官方 SDK 中都有对应类型(原文档的 API 链接指向 C++、Python、Rust 三个入口):
- Python:
rerun.encodings.ColorModel(ColorModel.RGB、ColorModel.L等),类型定义与扩展逻辑位于 encodings/color_model.py 与 encodings/color_model_ext.py; - Rust:
rerun::encodings::ColorModel,生成代码位于 color_model.rs,扩展方法在 color_model_ext.rs; - C++:
rerun::encodings::ColorModel,可通过rerun::Image记录图像。
一个典型的使用场景是:从 OpenCV 读入的帧是 BGR 内存布局,若不转换而直接记录,渲染端会得到错误的颜色通道。正确的做法是:
- 要么在记录时显式声明
ColorModel.BGR(配合ChannelDatatype.U8),让 Rerun 知道通道顺序并正确渲染; - 要么先转换成 RGB 再以
ColorModel.RGB记录。
Python 端as_pil_image的通道重排逻辑(image_ext.py 第 302-313 行)证明渲染管线确实会按ColorModel声明的顺序解释字节。
八、总结与延伸阅读
ColorModel虽只是一个小枚举,却是 Rerun 图像数据模型的基石之一:它定义了颜色通道的结构与顺序(L/RGB/RGBA/BGR/BGRA),与ChannelDatatype一起构成像素格式的完整描述,并在ImageFormat中被PixelFormat所覆盖。理解它,就能正确记录灰度图、RGB 相机帧、OpenCV BGR 数据与带透明度图像,也能读懂 SDK 在通道数校验、PIL 转换和 JPEG 压缩中的种种行为。
想进一步深入,可继续阅读仓库内的这些资料:
- 数据类型参考:channel_datatype.md、pixel_format.md、image_format.md;
- 图元定义:
archetypes.Image与其扩展实现 image_ext.py; - Rust 类型定义:color_model.rs、color_model_ext.rs;
- Python 测试用例:test_image.py。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考