恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Rerun 实战:使用 NV12 像素格式流式显示摄像头视频
首页
资讯中心
/
Rerun 实战:使用 NV12 像素格式流式显示摄像头视频
Rerun 实战:使用 NV12 像素格式流式显示摄像头视频
发布时间:2026/9/17 19:20:15
Rerun 实战使用 NV12 像素格式流式显示摄像头视频【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun本篇技术指南围绕 Rerun 官方示例 examples/python/nv12/README.md 展开讲解如何把摄像头采集到的 NV12YUV 4:2:0编码视频帧通过 Rerun SDK 的rr.Imagerr.PixelFormat.NV12接口实时可视化。读完本文你将掌握 NV12 的内存布局原理、BGR→NV12 的转换实现、PixelFormat枚举的语义以及 Rerun 渲染器在 GPU 侧完成 YUV→RGB 转换的底层机制可直接迁移到其他非 RGB 摄像头像素格式I420、YUY2 等的接入场景。示例背景为什么需要非 RGB 像素格式大多数摄像头硬件尤其是 USB 摄像头、嵌入式视觉传感器和视频解码芯片原生输出的是 YUV 系像素格式而不是 RGB。原因在于 YUV 色彩空间将亮度Y与色度U/V分离并允许对色度通道进行下采样以压缩带宽这正是 NV12 这类格式每像素仅需 12 位的由来。Rerun 的图像组件rr.Image默认支持通过ColorModel如 RGB、L与ChannelDatatype如 U8描述的普通图像但面对带有色度下采样chroma downsampling或每通道位数不同的格式时就需要使用rr.PixelFormat枚举来精确描述。官方文档中对该枚举的定位描述为“一些图像格式存在色度下采样和/或每通道位数不同这正是PixelFormat存在的意义且所有这些格式都支持随机访问”见 pixel_format.py。本示例正是这一能力的最小完整落地从摄像头实时读取帧、在 CPU 上转换为 NV12、按原始像素字节流式日志到 Rerun 查看器。快速运行两条命令启动 NV12 视频流原文档给出的运行方式非常精简两条命令即可完成安装与启动pip install -e examples/python/nv12 python -m nv12第一条命令以可编辑模式-e安装示例包第二条以模块方式运行主程序。从 pyproject.toml 可以看到该示例的完整依赖与入口声明[project] name nv12 version 0.1.0 readme README.md dependencies [rerun-sdk0.10, opencv-python, numpy] [project.scripts] nv12 nv12:mainrerun-sdk0.10Rerun 的 Python SDK代码中以import rerun as rr引入即pip install rerun-sdkopencv-python负责摄像头采集与色彩空间转换cv2.VideoCapture、cv2.cvtColornumpy负责帧数据的平面重排与打包。[project.scripts]声明了nv12 nv12:main因此安装后也可直接运行nv12命令效果等同于python -m nv12。运行前提示例通过cv2.VideoCapture(0)打开默认摄像头若机器无摄像头会抛出RuntimeError(This example requires a webcam.)。源码拆解NV12 流的完整实现示例核心代码位于 nv12.py全流程可划分为三个环节BGR→NV12 转换、命令行参数与 Rerun 会话初始化、逐帧日志。1. BGR→NV12 转换函数OpenCV 的VideoCapture默认返回 BGR 帧而目标格式是 NV12因此需要显式转换。bgr2nv12函数利用 OpenCV 已有的 I420 转换再重排为 NV12def bgr2nv12(bgr: cv2.typing.MatLike) - cv2.typing.MatLike: yuv cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV_I420) uv_row_cnt yuv.shape[0] // 3 uv_plane np.transpose(yuv[uv_row_cnt * 2 :].reshape(2, -1), [1, 0]) yuv[uv_row_cnt * 2 :] uv_plane.reshape(uv_row_cnt, -1) return yuv理解这段代码需要先明确两种 YUV 4:2:0 布局的区别I420Y_U_V12完全平面fully planar布局。整幅图像的 Y 数据独占一个平面随后是各占一半分辨率的 U 平面和 V 平面三平面完全分离NV12Y_UV12半平面semi-planar布局。Y 平面之后紧跟着一个 U、V 交错排列的平面行内顺序为U0, V0, U1, V1, …。因此转换逻辑为先用COLOR_BGR2YUV_I420得到 I420 布局此时缓冲区第 3 段索引2 * uv_row_cnt之后是独立的 U、V 两平面再将这两行数据转置交错np.transpose(..., [1, 0])后重新 reshape 成uv_row_cnt行即可得到 U/V 交错的 NV12 半平面。这里的uv_row_cnt即色度平面的行数等于高度的一半。注意OpenCV 的COLOR_BGR2YUV_I420输出的是 limited rangeY 在 [16,235]U/V 在 [16,240]与 Rerun 对 NV12 的默认解释一致无需额外缩放。2. 参数解析与会话初始化parser argparse.ArgumentParser(descriptionExample of using the Rerun visualizer to display NV12 images.) rr.script_add_args(parser) parser.add_argument( -t, --timeout, typefloat, default5, helpTimeout in seconds, after which the script will stop streaming frames., ) args parser.parse_args() rr.script_setup(args, rerun_example_nv12)rr.script_add_args与rr.script_setup/rr.script_teardown是 Rerun SDK 提供的脚本化辅助 API会自动处理--serve、--connect、--save等通用参数例如rr.script_setup返回一个可用于日志的RecordingStream。--timeout默认 5 秒控制本次采集持续时间方便自动演示。3. 主循环逐帧日志 NV12 图像cap cv2.VideoCapture(0) if not cap.isOpened(): raise RuntimeError(This example requires a webcam.) start_time time.time() print(fStarted streaming NV12 images for {args.timeout} seconds.) while start_time args.timeout time.time(): ret, frame cap.read() if not ret: time.sleep(0.01) continue rr.log( NV12, rr.Image( bytesbytes(bgr2nv12(frame)), widthframe.shape[1], heightframe.shape[0], pixel_formatrr.PixelFormat.NV12, ), ) time.sleep(0.01) rr.script_teardown(args)关键点是rr.Image的“原始字节”构造方式不传入 numpy 数组或路径而是显式传入三个参数bytesNV12 编码后的原始字节流bytes(bgr2nv12(frame))width/height图像尺寸取自帧的shape[1]/shape[0]pixel_formatrr.PixelFormat.NV12告知 Rerun 如何解读这段字节。由于 NV12 是 12 位/像素的压缩格式仅凭宽高无法推断数据布局pixel_format参数必不可少。循环每帧调用rr.log记录到实体路径NV12下从而在时间轴上形成连续的视频流。深入 PixelFormatNV12 在 Rerun 类型系统中的定义rr.PixelFormat是一个由代码生成器从类型定义自动生成到 Python / Rust / C 三端的枚举。其权威来源是 pixel_format.def.rs其中对 NV12 的完整描述为NV12又称Y_UV12是一种 YUV 4:2:0 色度下采样格式每像素 12 位、每通道 8 位。采用 limited range YUV即 Y 预期在 [16, 235]U/V 在 [16, 240]。内存布局为先整幅图像的 Y 平面随后是行内按U0, V0, U1, V1, …顺序交错的色度平面。对应的 Python 端定义生成于 pixel_format.pyNV12 26。值得注意两点枚举数值刻意对齐了 Ocean 库Frame类的预定义像素格式编号但源码注释明确说明“这不是严格依赖实现不应依赖该数值”仅为降低未来变更风险在 Rust 侧定义中NV12被标注为#[default]即它是PixelFormat的默认变体这也侧面说明 NV12 是该类型最常见的应用场景。同一枚举还覆盖了其他常见摄像头/视频格式可在接入不同硬件时直接复用枚举变体布局说明NV12Y_UV12YUV 4:2:0 半平面12 位/像素limited range本示例所用Y_U_V12_LimitedRange/Y_U_V12_FullRangeYUV 4:2:0 全平面I420三平面分离仅 range 不同YUY2YUYVYUV 4:2:2 单平面16 位/像素行序Y0,U0,Y1,V0Y_U_V16_LimitedRange/Y_U_V16_FullRangeYUV 4:2:2 全平面I422半分辨率仅体现在水平方向Y_U_V24_LimitedRange/Y_U_V24_FullRangeYUV 4:4:4 全平面I444无色度下采样Y8_FullRange/Y8_LimitedRange单色 Y 平面灰度图区别在 range底层原理查看器如何把 NV12 绘制到屏幕从 image_to_gpu.rs 的源码看PixelFormat在进入渲染管线前会被映射为 GPU 端的SourceImageDataFormatPixelFormat::NV12→SourceImageDataFormat::Yuv { layout: YuvPixelLayout::Y_UV420 }PixelFormat::Y_U_V12_*→YuvPixelLayout::Y_U_V420PixelFormat::YUY2→YuvPixelLayout::YUYV422等等。同时会根据像素格式推导两个关键参数YUV 转换矩阵系数调用pixel_format.yuv_matrix_coefficients()得到Bt601或Bt709源码注释指出 NV12 通常按 BT.601 处理但仍留有 TODO 进一步确认底层预期YUV range调用is_limited_yuv_range()判断是YuvRange::Limited8 位数据 Y∈[16,235]、U/V∈[16,240]还是YuvRange::Full各分量 0~255。实际执行 YUV→RGB 转换的是渲染器中的 yuv_converter.rs配套 WGSL 着色器yuv_converter.wgsl。该模块对术语做了澄清性注释“我们混用 YUV/YCbCr/YPbPr通常统称 YUV其中 YCbCr 是数字信号中经过缩放与偏移的 YUV即本文所说的 limited range YUV”并提到 OpenCV 在谈论 full range 时使用 YCbCr、谈论 limited range 时使用 YUV——这与示例中COLOR_BGR2YUV_I420输出 limited range 的行为相互印证。转换过程中会根据YuvMatrixCoefficients与YuvRange生成对应的转换矩阵与缩放偏移保证色度下采样格式在 GPU 上正确重建 RGB。换言之从rr.Image(bytes..., pixel_formatrr.PixelFormat.NV12)到屏幕像素数据流为CPU 端字节流 → SDK 按ImageFormat编码 → 查看器识别PixelFormat→ GPU 上传并依据 YUV 布局 / 矩阵 / range 在着色器中完成 YUV→RGB → 最终绘制。示例与渲染链路共同构成一个自洽的参考实现。迁移指南把该模式应用到你的项目抛开 Webcam 这一具体场景本示例展示的通用接入模式适用于任何输出 YUV 系格式的视觉数据源相机 SDK、解码器、嵌入式设备确认硬件像素格式查阅摄像头/解码器的输出格式如 NV12、I420、YUY2并明确其 YUV rangelimited/full与矩阵系数BT.601/BT.709——这与 Rerun 端PixelFormat的语义必须一致转换为 Rerun 期望的布局若源数据是 BGR/RGB先经色彩空间转换若源格式是 I420 而目标为 NV12可按示例中的bgr2nv12思路做平面重排同样可用np.transposereshape完成 U/V 交错以原始字节构造rr.Image传入bytes、width、height与pixel_format四个要素逐帧rr.log到同一实体路径即可形成视频流其他格式复用无需修改日志代码只需替换pixel_format枚举值如rr.PixelFormat.YUY2或rr.PixelFormat.Y_U_V12_LimitedRange并确保字节布局与之匹配。通过以上四步你可以像本示例一样把任意非 RGB 摄像头格式以零冗余字节的方式直接可视化并利用 Rerun 的时间轴浏览、蓝图层叠加等能力进行后续分析。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考