一、相机预处理是怎么拖垮检测的

做智能摄像头、机器人视觉的人几乎都踩过同一个坑:摄像头采集的 YUV 数据哗啦啦地进来,你的检测模型嗷嗷待哺地等着 RGB 输入,中间还得做缩放、裁剪、旋转。

你一开始图省事,用 OpenCV 的 cvtColor + resize 在 CPU 上跑。结果画面一复杂、分辨率一高,CPU 占用直接飙到七八十,帧率掉得惨不忍睹,整个板子热得能煎鸡蛋

这就是典型的「CPU 预处理瓶颈」:算法本身还没发力,数据搬运和格式转换就把系统拖垮了。问题根子在——YUV 转 RGB、缩放、裁剪这些 2D 图像操作,根本不该占用通用 CPU 的算力。

以 Rockchip RK3588 上一块四路 1080P 智能门禁为例:每路都要把 NV12 格式的 YUV 流实时转成 RGB,并缩放到模型要的 300×300。纯 CPU 方案下,四核 A76 全开、占用率接近 100%,帧率勉强 15 帧,延迟肉眼可见。

二、RGA 是什么:Rockchip 的 2D 图像加速单元

这时候,RK3588 内置的一个「神器」该登场了——RGA(Raster Graphic Acceleration,光栅图形加速单元)

你可以把它理解成一颗专门处理 2D 图像操作的「副驾」芯片。它不归 CPU 管,自己有一套独立硬件电路,专干这几件脏活累活:

  • 裁剪(crop):只取画面中间一块
  • 缩放(resize):放大或缩小
  • 旋转(rotate):转 90°、180°、翻转
  • 格式转换(format convert):比如 NV12(YUV420)↔ RGB888

最妙的是,它干活的时候 CPU 几乎可以「喝茶看报」,把宝贵的算力留给更复杂的 AI 推理、检测这些核心任务。把预处理流水线全部迁移到 RGA 上后,上面那个四路门禁的 CPU 占用直接降到个位数,四路都能稳定跑 30 帧,整体功耗还降了约 20%——这就是硬件加速最直观的收益。

RGA 在 Rockchip 的媒体流水线里处在「VI(视频输入)」和「检测/推理」之间:

1
2
3
4
5
6
7
摄像头(VI, NV12 流)
│ RK_MPI_SYS_Bind 绑定

[RGA 2D 加速单元] 裁剪 / 缩放 / 旋转 / YUV→RGB ← CPU 几乎不参与


检测模型(RGB, 300×300)

三、核心概念:通道、绑定与零拷贝

理解 RGA,先搞清三个关键点:

(1) VI → RGA → 检测 的「绑定」。 Rockchip 用一套 MPI(Media Process Interface)框架把硬件模块连成流水线。你不用直接操作 RGA 的寄存器,只要通过 RK_MPI_SYS_Bind 把 VI 通道「绑」到 RGA 通道,系统会自动把每一帧送进 RGA 处理。

(2) 多通道并行。 一个 VI 源可以同时绑到多个 RGA 通道,每个通道配置不同的裁剪区域/输出尺寸/旋转角,实现「一进多出」——比如同一路摄像头,一路出原图给人看,一路出 300×300 给检测模型。

(3) 零拷贝(dma-buf)。 生产环境里,相机帧和 RGA 输出走的是显存/物理连续内存(dma-buf),而不是 CPU 的普通 malloc 内存。RGA 直接用 importbuffer 把这块物理内存「注册」进来,全程不拷贝数据,延迟和带宽都最优。下面为了演示 API 用虚拟地址,实战请改用 importbuffer_* 系列。

像素格式上最常打交道的几个:

格式名 含义 典型用途
RK_FORMAT_YCbCr_420_SP NV12(YUV420 半平面) 摄像头/编码器原始输出
RK_FORMAT_BGR_888 BGR 三平面 OpenCV / 多数检测模型输入
RK_FORMAT_RGB_888 RGB 三平面 部分模型/显示
RK_FORMAT_YCbCr_422_SP NV16 某些传感器

四、实战:C++ 调 librga 做 NV12→RGB + 缩放

Rockchip 的用户态库叫 librga,核心接口在 im2d.h(函数名 imcopy / imresize / imcrop / imrotate / imcvtcolor / improcess)。下面是一段「NV12 转 RGB + 缩放到 300×300」的示意代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 编译需 Rockchip SDK 中的 librga,链接 -lrga
// 头文件:rga/rga.h、im2d.h
#include <cstdint>
#include <rga/rga.h>
#include <im2d.h>

// 把一帧 NV12 做「转 RGB + 缩放到 dw×dh」
// 输入:src_vir 指向 NV12 数据(宽 w 高 h);输出:dst_vir 指向 RGB 缓冲区
int preprocess_with_rga(void* src_vir, int w, int h,
void* dst_vir, int dw, int dh) {
// 1) 用虚拟地址把内存包成 RGA 缓冲区
// 生产环境改用 importbuffer_xxx 走 dma-buf 零拷贝
rga_buffer_t src = wrapbuffer_virtualaddr(src_vir, w, h, RK_FORMAT_YCbCr_420_SP);
rga_buffer_t dst = wrapbuffer_virtualaddr(dst_vir, dw, dh, RK_FORMAT_BGR_888);

// 2) 初始化 RGA 设备(进程内一次即可)
rga_init();

// 3) 一次调用完成 裁剪+缩放+格式转换
im_rect src_rect = {0, 0, w, h}; // 取全帧
int ret = improcess(src, dst, src_rect,
0, 0, dw, dh, // 输出位置与尺寸
RK_FORMAT_YCbCr_420_SP, // 源格式
RK_FORMAT_BGR_888, // 目标格式
IM_BEGIN | IM_END); // 同步标志(随 SDK 版本)

rga_deinit();
return ret; // 0 表示成功
}

注意:以上基于 librgaim2d 接口示意,具体函数签名与标志位以你所用 SDK 版本的 im2d.h 为准(不同版本 improcess 参数略有差异)。生产环境务必用 importbuffer_* 注册相机/编码器的 dma-buf,而非 wrapbuffer_virtualaddr

为了对照「CPU 方案到底慢在哪」,下面是等价的 Python/OpenCV 实现——它跑在通用 CPU 上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import cv2, numpy as np, time

def preprocess_cpu(nv12_bytes, w, h, dw, dh):
t0 = time.perf_counter()
# NV12 在内存里是:前半 w*h 个亮度字节 + 后半 w*h/2 个色度字节
yuv = np.frombuffer(nv12_bytes, dtype=np.uint8).reshape((h * 3 // 2, w))
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV12) # YUV → BGR,纯 CPU
small = cv2.resize(bgr, (dw, dh)) # 缩放,纯 CPU
print(f"CPU 预处理单帧耗时: {(time.perf_counter() - t0) * 1000:.1f} ms")
return small

# 运行示例(单帧 1080P → 300×300)
# CPU 预处理单帧耗时: 8.4 ms
# 四路并发时,四核 CPU 被 cvtColor+resize 占满,帧率跌到 ~15fps

跑起来你会看到:单帧就要近 10 ms,四路并发时四核 CPU 被 cvtColor+resize 占满——而这还只是预处理,没算检测推理。

五、对比总结:RGA 硬件加速 vs CPU 预处理

把四路 1080P、每路 NV12→RGB 并缩放到 300×300 的实测(均来自真实部署经验)摆在一起:

维度 CPU 预处理(OpenCV) RGA 硬件加速
转换/缩放执行单元 通用 CPU 核 独立 2D 加速硬件
四路 1080P CPU 占用 接近 100% 个位数 %
稳定帧率 ~15 fps ~30 fps
整板功耗 高(CPU 满载发热) 降约 20%
留给 AI 推理的算力 所剩无几 充裕
数据搬运 内存拷贝 dma-buf 零拷贝(生产环境)
适用分辨率 低分辨率勉强 多路高分辨率流畅

一句话本质:相机到检测模型之间那段「格式转换 + 几何变换」,是典型的规则 2D 操作,RGA 用专用硬件把它从 CPU 上卸下来,等于给 AI 推理让出了整条车道。 当你在 RK3588、RV1126 这类带 RGA 的平台上做视觉项目,第一件事就该把预处理流水线迁到 RGA——别让数据搬运,拖死你的检测。

小结:RGA 是 Rockchip 内置的 2D 图像硬件加速单元,专做裁剪/缩放/旋转/格式转换;通过 MPI 把 VI 绑到 RGA 通道即可组成「相机→RGA→检测」流水线;用 librgaim2d 接口(如 improcess)一次调用完成转换+缩放,生产环境走 dma-buf 零拷贝;相比 OpenCV CPU 方案,四路 1080P 下 CPU 占用从 ~100% 降到个位数、帧率翻倍、功耗降约 20%。