FPGA+ARM实现AWB的全流程

一、FPGA实现AWB的方式

1.fpga实时统计灰点区域内的R/G/B分量求和

2.fpga实时统计灰点区域内的像素计数

3.awb_process()函数做白平衡校准的增益计算,以及做置信度的判断和限幅处理

4.将R/G/B颜色增益寄存器写入到逻辑AWB算法IP

二、AWB核心原理

灰度世界法+灰点椭圆/矩形区域法

1.计算每个像素的色度比rg = R/G,bg=B/G

2.硬件只统计落入"灰色区域"(AWB 窗口)内的像素:以参考灰点 (center_rg, center_bg) 为中心、rg_radius/bg_radius 为半宽的区域(配合 h_rg/l_rg/h_bg/l_bg 上下界、ymin/ymax 亮度范围过滤);

3.累加区域内的 ΣR、ΣG、ΣB 和像素计数 ΣN;

4.cpu计算

--若 ΣN 占总像素比例不足 awb_pcnt_(置信度不足),保持旧增益;

--否则计算 rcoe = ΣG/ΣR(即 1/(ΣR/ΣG)),bcoe = ΣG/ΣB,gcoe = 1;

--用 awb_ycoe_ 做亮度补偿(保持统计亮度不变),并限幅到 0.8, 1.2 附近;

--写回增益寄存器

--awb_init_radius 的作用即根据 h/l 上下界初始化灰点中心和半径。

三、关键代码

1.结构体成员

/* ---- AWB 运行时数据 ---- */

float awb_center_rg_; // 灰点中心 rg = (h_rg + l_rg) / 2

float awb_center_bg_; // 灰点中心 bg = (h_bg + l_bg) / 2

float awb_rcoe_; // 当前 R 增益

float awb_gcoe_; // 当前 G 增益

float awb_bcoe_; // 当前 B 增益

u32 total_pix_cnt_; // 全帧像素数 = rows * cols

2.灰点区域初始化

/* 由 h/l 上下限推算灰点中心与椭圆半径

* center = (high + low) / 2

* radius = (high - low) / 2 (并限制最大半径,防止区域过大失去灰点意义)

*/

static void awb_init_radius(AWB* ths)

{

float h_rg = ths->param_.awb_h_rg_.get_value(&ths->param_.awb_h_rg_);

float l_rg = ths->param_.awb_l_rg_.get_value(&ths->param_.awb_l_rg_);

float h_bg = ths->param_.awb_h_bg_.get_value(&ths->param_.awb_h_bg_);

float l_bg = ths->param_.awb_l_bg_.get_value(&ths->param_.awb_l_bg_);

ths->awb_center_rg_ = 0.5f * (h_rg + l_rg);

ths->awb_center_bg_ = 0.5f * (h_bg + l_bg);

float r1 = h_rg / (ths->awb_center_rg_ + 0.01f) - 1.0f; // 0.01 防除0

float r2 = h_bg / (ths->awb_center_bg_ + 0.01f) - 1.0f;

if (r1 > 0.3f) r1 = 0.3f; /* rg_radius 上限 */

if (r2 > 0.3f) r2 = 0.3f; /* bg_radius 上限 */

ths->param_.awb_rg_radius_.set_value(&ths->param_.awb_rg_radius_, r1);

ths->param_.awb_bg_radius_.set_value(&ths->param_.awb_bg_radius_, r2);

/* 同步到 FPGA 寄存器(低16位/高16位拆分,Q格式) */

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_CENTER_RG, ths->awb_center_rg_);

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_CENTER_BG, ths->awb_center_bg_);

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_RG_RADIUS, r1);

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_BG_RADIUS, r2);

}

3.awb_process核心处理步骤

static void awb_process(AWB* ths)

{

XhlsIsp3AParam* p = &ths->param_;

/* 0. 手动模式:仅透传手动增益,不做统计闭环 */

if (p->awb_auto_.get_value(p->awb_auto_) == 0) {

ths->awb_rcoe_ = p->awb_rcoe_.get_value(p->awb_rcoe_);

ths->awb_gcoe_ = p->awb_gcoe_.get_value(p->awb_gcoe_);

ths->awb_bcoe_ = p->awb_bcoe_.get_value(p->awb_bcoe_);

awb_write_gain(ths);

return;

}

u32 r_sum = ths->base_.regs_.get_value(&ths->base_.regs_, AWB_STAT_R_SUM);

u32 g_sum = ths->base_.regs_.get_value(&ths->base_.regs_, AWB_STAT_G_SUM);

u32 b_sum = ths->base_.regs_.get_value(&ths->base_.regs_, AWB_STAT_B_SUM);

u32 n_cnt = ths->base_.regs_.get_value(&ths->base_.regs_, AWB_STAT_PIX_CNT);

float pcnt = p->awb_pcnt_.get_value(p->awb_pcnt_);

if (n_cnt < (u32)(ths->total_pix_cnt_ * pcnt) || n_cnt == 0) {

return; /* 样本不足,保持上一帧增益 */

}

if (g_sum == 0) return; /* 防除0 */

float rg_aver = (float)r_sum / (float)g_sum; /* ΣR / ΣG */

float bg_aver = (float)b_sum / (float)g_sum; /* ΣB / ΣG */

float rcoe = 1.0f / (rg_aver + 0.01f);

float gcoe = 1.0f;

float bcoe = 1.0f / (bg_aver + 0.01f);

float ycoe = p->awb_ycoe_.get_value(p->awb_ycoe_);

rcoe = rcoe * (1.0f - ycoe) + ycoe * gcoe;

bcoe = bcoe * (1.0f - ycoe) + ycoe * gcoe;

rcoe = STD_MAX(0.8f, STD_MIN(1.2f, rcoe));

bcoe = STD_MAX(0.8f, STD_MIN(1.2f, bcoe));

ths->awb_rcoe_ = rcoe;

ths->awb_gcoe_ = gcoe;

ths->awb_bcoe_ = bcoe;

awb_write_gain(ths);

}

static void awb_write_gain(AWB* ths)

{

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_R_COE, ths->awb_rcoe_);

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_G_COE, ths->awb_gcoe_);

ths->base_.regs_.set_value_float(&ths->base_.regs_, AWB_REG_B_COE, ths->awb_bcoe_);

}

四、参数说明

1.参数协同逻辑

┌─ ymin/ymax:亮度窗口过滤

像素筛选 ─────┤

└─ (rg∈l_rg, h_rg) 且 (bg∈l_bg, h_bg),且在半径 rg_radius/bg_radius 内

↓

统计:ΣR、ΣG、ΣB、ΣN ──→ pcnt 置信度门槛(不足则冻结增益)

↓

增益:rcoe=ΣG/ΣR, bcoe=ΣG/ΣB ──→ ycoe 亮度补偿 ──→ 0.8,1.2 限幅 ──→ 写回寄存器

--偏色严重难收敛 → 放大 rg_radius/bg_radius、降低 awb_pcnt_;

--画面易被彩色物体带偏 → 缩小半径、提高 pcnt、收紧 h/l_rg、h/l_bg;

--白平衡切换时画面闪烁 → 提高 ycoe(亮度补偿)或软件上对增益做斜坡过渡;

--暗场/逆光场景偏色 → 调整 ymin_/ymax_ 把无效像素排除出统计。

2.参数说明

参数

awb_mode:AWB 模块使能,其中0=关闭(透传),1=使能写入 CTRL bit0;菜单可切换

awb_auto:自动/手动模式,其中1=自动闭环(统计→计算增益→写回);0=手动,直接使用下面的 r/g/b 系数

awb_rcoe:R 通道增益,手动模式或自动模式下写回的当前 R 增益,典型 0.5~2.0

awb_gcoe:G 通道增益,灰世界法中固定为 1.0(G 作为归一化基准)

awb_bcoe:B 通道增益,同 rcoe,对应 B 通道

awb_ycoe:亮度补偿系数 0~1:rcoe' = rcoe·(1−ycoe) + ycoe。ycoe 越大,白平衡调整时越倾向保持亮度恒定,防止画面整体明暗跳变;典型 0.3~0.5

awb_pcnt:置信度阈值 灰点区域内像素数占全帧的最小比例(如 0.1 即 10%)。低于该值认为统计不可靠(场景无有效灰点/大面积单一色),保持上一帧增益不更新,防止误收敛

awb_h_rg:灰点区域 rg 上限 判定"灰色像素"时允许的最大 R/G 比,如 1.2

awb_l_rg:灰点区域 rg 下限 允许的最小 R/G 比,如 0.8

awb_h_bg:灰点区域 bg 上限 允许的最大 B/G 比,如 1.2

awb_l_bg:灰点区域 bg 下限 允许的最小 B/G 比,如 0.8

awb_rg_radius:rg 方向灰点半径 由 init_radius 依据 (h_rg−l_rg)/2 计算,限制在 0.3 以内;半径越大,允许参与统计的"近似灰"像素越多(收敛快但易受彩色物体干扰)

awb_bg_radius:bg 方向灰点半径 同上,作用于 B/G 方向

awb_ymin:亮度过滤下限 Y 低于该值的暗像素不参与统计(避免暗噪声使白平衡偏移)

awb_ymax:亮度过滤上限 Y 高于该值的过曝像素不参与统计(过曝像素 RGB 相等、无色度信息)

五、灰度区域调整

灰点区域 指在 R/G(rg)- B/G(bg)色度平面上判定"该像素接近灰色"的判定窗口,由以下参数共同控制:

判定条件:l_rg ≤ rg ≤ h_rg 且 l_bg ≤ h_bg 之间

且到中心点的归一化距离 ≤ 半径

中心:center_rg = (h_rg + l_rg) / 2

半径:radius = (h_rg - l_rg) / 2 (awb_init_radius 计算,上限 0.3)

六、置信度阈值设置

本帧落在灰点区域内的像素数 n_cnt,必须达到全帧总像素数 total_pix_cnt_ × awb_pcnt_,本次白平衡计算才有效;否则冻结上一帧增益,防止误收敛。

过低(<0.05):少量彩色噪声即可改变白平衡,画面易"漂色";

过高(>0.5):光源变化时长时间不更新,色彩偏移不能及时纠正;

该值只影响更新频率门槛,不影响每次更新的增益计算精度,应与灰点区域大小配合调整:区域小 → pcnt 适当调低;区域大 → pcnt 适当调高。

七、增益限幅

  1. 防止单帧突变(闪烁)

光源瞬间变化或统计噪声导致计算的增益异常(例如 rg 突然变成 2.0 → rcoe = 0.5),若不限幅,画面会在一帧内发生剧烈色偏跳变。限幅把每帧最大调整量限制在 ±20%,保证过渡平滑。

  1. 防止算法误收敛

当灰点区域被彩色物体占据(例如大面积红色屋顶),灰世界假设失效,可能算出极端增益(如 rcoe=0.3、bcoe=1.8)。限幅作为最后一道安全网,即使前面 pcnt 置信度判断漏过,也不会让画面出现严重失真。

  1. 保护下游模块的动态范围

过大的通道增益会使该通道像素饱和截断(clip),破坏色度信息,影响后续 CCM(颜色校正矩阵)、Gamma 等模块的效果。±20% 的范围是白平衡增量调节的合理工程区间。

相关推荐
李洱44 分钟前
LangChain 和 LangGraph 的区别:核心原理与使用场景
算法
用户938515635071 小时前
从 0 到 1 搭建企业级多模态 RAG 知识库:一个装修公司的 AI 落地实战
人工智能·langchain·llm
Purple Coder1 小时前
M-H图像分析
人工智能
夏幻灵1 小时前
每日一题:LeetCode 206:反转链表——三指针与原地反转详解
算法·leetcode·链表
沛东的认知和实践1 小时前
能增、能删,但不幂等:拆开 WeKnora 的LLMWiki知识编译——彻底搞懂LLM Wiki第二篇
人工智能
两万五千个小时1 小时前
DeepSeek Harness 从 0 开始:20 goal模式
人工智能·程序员·架构
QuZhengRong1 小时前
【周报】2026-10-02~10-08 AI 科技周报
人工智能·科技·新闻
云沛科技1 小时前
在实验室复刻暴风雪:低温雨雪冰雾耦合试验室解锁极端环境 “实景仿真”
人工智能·功能测试·科技
程序员大狐狸1 小时前
Ultra X7 358H 笔记本电脑,本地部署当红炸子鸡 Qwen3.8-27B-Q4,实测生成速度 5.6 tok/s
人工智能