统计信息采集:R/G/B通道统计、区域统计与权重、YUV域统计、RK平台统计寄存器配置

各位做ISP的兄弟,咱们今天聊聊AWB最基础、也最容易被忽视的一环——统计信息采集。

说白了,AWB算法再牛,如果前端统计信息不准,后面全是白搭。我当年刚接手RK平台时,就吃过这个亏。白平衡怎么调都偏色,折腾了两周,最后发现是统计窗口配置错了。嗯,从那以后,我养成了一个习惯:先看统计,再调算法。

4.1 R/G/B通道统计——AWB的“眼睛”

AWB的核心任务,是估计场景中的色温。怎么估计?靠的就是R、G、B三个通道的统计值。

每个像素点进来,ISP硬件会分别累加R、G、B的亮度值。同时还会统计像素个数,这样我们就能算出平均值。

核心公式(硬件帮你算好了):

  • R_avg = sum(R) / pixel_count
  • G_avg = sum(G) / pixel_count
  • B_avg = sum(B) / pixel_count

这三个值,就是AWB算法的输入。后面所有的色温估计、增益计算,都基于它们。

你可能会问:直接全图平均不就行了?

没那么简单。如果场景里有一块大面积纯色物体,比如红墙、绿草地,全图平均会把AWB带偏。所以,我们需要更精细的统计方式。

4.2 区域统计与权重——让算法“看”得更聪明

RK平台的ISP,会把整幅图像划分成M×N个统计块(block)。每个块独立统计R、G、B的累加值和像素数。

我个人习惯把图像分成15×15或17×17的网格。为什么是这个数?因为RK3588的统计寄存器宽度刚好能支持到32×32,但分太细了,后续处理负担重;分太粗了,又没法排除异常区域。

分好块之后,关键一步来了——给每个块分配权重。

区域类型 权重建议 说明
画面中央区域 高(如2.0~4.0) 主体通常在这里,优先保证中央色温准确
画面边缘区域 中(如1.0~1.5) 边缘可能有镜头暗角,权重不宜过高
过曝/欠曝区域 0(排除) 亮度超出统计范围的数据,直接丢弃
纯色大块区域 低(如0.1~0.3) 通过色度阈值判断,降低其对全局的影响

我的经验:权重配置不要一刀切。我曾经在一个户外监控项目里,把中央权重设到5.0,结果画面边缘偏色严重。后来改成中央2.5、边缘1.0、四角0.8,效果就好多了。调试时,建议先看统计值的分布图,再调权重。

4.3 YUV域统计——另一种视角

除了RGB统计,RK平台还提供了YUV域的统计信息。为什么需要YUV?

因为RGB三个通道相关性太强。比如一个物体从亮处移到暗处,R、G、B同时变化,但色度(Cb、Cr)相对稳定。YUV统计,说白了就是把亮度和色度分开看。

YUV统计主要提供以下信息:

  • Y直方图:256级亮度分布,用于判断场景整体亮度
  • Cb、Cr均值:反映整体色偏方向
  • Cb、Cr二维直方图:256×256的色度分布,这是AWB算法的“金矿”

我记得在做一个室内灯光复杂的项目时,RGB统计出来的色温一直在3000K~6000K之间跳变。后来我看了Cb-Cr二维直方图,发现有两个明显的聚类——一个是暖色灯区域,一个是窗边自然光区域。用这个信息做多区域AWB,问题就解决了。

4.4 RK平台统计寄存器配置——动手实战

理论说完了,咱们看看RK3588上怎么配寄存器。这部分是硬核内容,我建议你对照RK的TRM手册一起看。

4.4.1 统计窗口配置

首先,要告诉ISP统计哪块区域。默认是全图,但你可以裁剪。

// RK3588 AWB统计窗口配置示例
// 寄存器基址:AWB_CTRL_BASE = 0xFD8C0000

// 1. 使能AWB统计模块
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0000) |= (1 << 0);

// 2. 设置统计窗口起始坐标 (x_start, y_start)
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0004) = (100 << 16) | 80;  // x=100, y=80

// 3. 设置统计窗口结束坐标 (x_end, y_end)
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0008) = (1900 << 16) | 1080; // x=1900, y=1080

// 4. 设置分块数:水平17块,垂直13块
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x000C) = (17 << 16) | 13;

注意:窗口坐标的单位是像素,但分块数必须是奇数。为什么?因为中央块正好对应画面中心。RK的硬件设计如此,如果你设成偶数,中央区域会落在两块之间,权重计算会很麻烦。

4.4.2 权重表配置

权重表是一维数组,按行优先顺序写入。每个块对应一个8位权重值(0~255)。

// 权重表配置(17×13 = 221个权重值)
// 寄存器地址连续,从 0x0010 开始
uint8_t weight_table[221];
// 填充权重值...
// 中央区域权重设200,边缘设100,四角设50

for (int i = 0; i < 221; i++) {
    *(volatile uint8_t*)(AWB_CTRL_BASE + 0x0010 + i) = weight_table[i];
}

这里有个坑:权重表写入后,硬件不会立即生效。你需要触发一次“统计更新”命令。

// 触发统计更新
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0000) |= (1 << 4);
// 等待更新完成
while (*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0000) & (1 << 4));

4.4.3 YUV统计配置

YUV统计的配置稍微复杂一点,需要设置Cb-Cr二维直方图的bin宽度。

// YUV统计配置
// 设置Cb、Cr的bin宽度:每个bin覆盖8个灰度级
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0100) = (8 << 8) | 8;

// 使能YUV统计
*(volatile uint32_t*)(AWB_CTRL_BASE + 0x0104) |= (1 << 0);

// 读取Y直方图(256个bin,地址从0x0200开始)
uint32_t y_hist[256];
for (int i = 0; i < 256; i++) {
    y_hist[i] = *(volatile uint32_t*)(AWB_CTRL_BASE + 0x0200 + i * 4);
}

避坑指南:我曾经把Cb-Cr的bin宽度设成4,结果直方图太稀疏,很多bin是空的。后来改成8,数据分布就合理了。具体设多少,取决于你的场景动态范围。一般建议8~16之间。

4.5 知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以把它当作调试时的检查清单。

AWB统计信息采集知识体系 AWB统计信息采集流程 Bayer RAW 图像输入 ISP硬件流水线 R/G/B通道统计 累加值 + 像素计数 区域统计与权重 M×N分块 + 权重表 YUV域统计 Y直方图 + CbCr二维图 RK平台统计寄存器配置 窗口坐标配置 分块数与权重表 YUV bin宽度配置 统计结果输出到AWB算法 关键:统计窗口、分块数、权重表、bin宽度——这四个参数决定了AWB的“视力”好坏

4.6 调试建议

最后,分享几个我在项目中积累的调试技巧:

  1. 先读后写:配置寄存器之前,先读一遍默认值。RK平台的默认值有时会变,别想当然。
  2. 验证统计窗口:在图像上叠加显示统计块的边界,确认窗口位置对不对。我见过有人把x_start和y_start写反了,结果统计的是画面外的数据。
  3. 权重可视化:把权重表转成灰度图,一眼就能看出权重分布是否合理。中央亮、边缘暗才是对的。
  4. YUV直方图检查:如果Cb-Cr二维直方图全集中在(128,128)附近,说明bin宽度太大,分辨率不够。如果分布太散,说明bin宽度太小。

重要提醒:统计配置改完后,一定要重新触发统计更新。我踩过这个坑——改了权重表,但忘了触发更新,结果算法读到的还是旧数据,白忙活半天。