目录
[1. 原理](#1. 原理)
[2. 实现](#2. 实现)
[3. 核心说明](#3. 核心说明)
[4. 关键执行约束](#4. 关键执行约束)

基于双目中性灰点的 UV 偏差,推导正确的 RGain/BGain 修正公式。
1. 原理
(1)YUV 与 RGB 的正确转换(BT601 为例,ISP 标配)
python
RGB→YUV(8bit,UV范围[-128,127],需归一化到[0,255]):
Y = 16 + (65.738*R + 129.057*G + 25.064*B)/256
U = 128 + (-37.945*R - 74.494*G + 112.439*B)/256
V = 128 + (112.439*R - 94.154*G - 18.285*B)/256
逆推:中性灰(R=G=B)时,U=128,V=128(归一化后);
若RGain偏大 → R>G=B → V>128;
若BGain偏大 → B>G=B → U<128;
若RGain偏小 → R<G=B → V<128;
若BGain偏小 → B<G=B → U>128。
(2)正确的修正逻辑
双目场景下,左图作为参考(WB 已校准),右图 UV 偏差 = 硬件差异 + WB 增益偏差,需先剔除硬件差异,再修正 WB:

2. 实现
python
import numpy as np
# 全局WB增益缓存队列(用于样本不足时的平滑,初始化默认值1.0)
wb_gain_queue = {
"RGain": [1.0] * 10, # 8.8定点数对应初始值256
"BGain": [1.0] * 10
}
def uv_adjust_wb_gain(U_l, V_l, U_r, V_r, Y_l, Y_r, mask, RGain_old, BGain_old, yuv_standard="BT601"):
"""
基于双目中性灰点UV偏差,调整右图WB的RGain/BGain(无冗余+工程化修正)
:param U_l/V_l: 左图公共区域U/V通道(参考,8bit,归一化后[0,255])
:param U_r/V_r: 右图公共区域U/V通道(待校正,8bit,归一化后[0,255])
:param Y_l/Y_r: 左/右图公共区域Y通道(用于校验内容一致性,8bit)
:param mask: 有效像素Mask(1=有效,0=无效)
:param RGain_old/BGain_old: ISP当前的RGain/BGain(浮点数,GGain=1)
:param yuv_standard: YUV色彩空间(BT601/BT709)
:return: 新的RGain、BGain(16bit 8.8定点数,ISP可直接写入)
"""
# 1. 严格筛选双目中性灰点(核心条件)
# 条件:① 有效Mask ② 左右目UV均接近中性灰 ③ 左右目亮度差小(内容一致)
mask_gray_l = ((np.abs(U_l - 128) <= 10) & (np.abs(V_l - 128) <= 10)).astype(np.uint8)
mask_gray_r = ((np.abs(U_r - 128) <= 10) & (np.abs(V_r - 128) <= 10)).astype(np.uint8)
mask_y_consist = (np.abs(Y_l - Y_r) <= 10).astype(np.uint8) # 亮度一致=内容一致
mask_final = mask & mask_gray_l & mask_gray_r & mask_y_consist
# 2. 提取双目中性灰点的UV
valid_U_l = U_l[mask_final == 1]
valid_V_l = V_l[mask_final == 1]
valid_U_r = U_r[mask_final == 1]
valid_V_r = V_r[mask_final == 1]
# 3. 样本量校验 + 空值保护(核心优化:样本不足时用历史平滑值)
valid_pix_num = len(valid_U_l)
if valid_pix_num < 50:
# 样本不足:返回队列中位数(8.8定点数),避免增益突变
stable_RGain = np.median(wb_gain_queue["RGain"])
stable_BGain = np.median(wb_gain_queue["BGain"])
RGain_new_fixed = int(stable_RGain * 256)
BGain_new_fixed = int(stable_BGain * 256)
return RGain_new_fixed, BGain_new_fixed
# 4. 计算双目UV偏差(仅WB导致的偏差,剔除硬件差异)
delta_U_wb = np.mean(valid_U_r) - np.mean(valid_U_l) # 右图U - 左图U
delta_V_wb = np.mean(valid_V_r) - np.mean(valid_V_l) # 右图V - 左图V
# 5. 正确推导RGain/BGain修正值(修正k值顺序)
# 系数k:UV偏差→WB增益的转换系数(BT601更敏感,k更小)
k = 0.0035 if yuv_standard == "BT601" else 0.004
RGain_new = RGain_old * (1 - delta_V_wb * k) # V偏多→RGain调小(减少红色)
BGain_new = BGain_old * (1 + delta_U_wb * k) # U偏多→BGain调大(增加蓝色)
# 6. 增益钳位(ISP硬件限制:±20%调整范围)
RGain_new = np.clip(RGain_new, 0.8, 1.2)
BGain_new = np.clip(BGain_new, 0.8, 1.2)
# 7. 更新WB增益缓存队列(用于后续样本不足时的平滑)
wb_gain_queue["RGain"].pop(0)
wb_gain_queue["RGain"].append(RGain_new)
wb_gain_queue["BGain"].pop(0)
wb_gain_queue["BGain"].append(BGain_new)
# 8. ISP适配:转换为16bit 8.8定点数(整数部分8bit,小数部分8bit)
# 示例:0.8→205 (0.8*256), 1.0→256, 1.2→307 (1.2*256)
RGain_new_fixed = int(RGain_new * 256)
BGain_new_fixed = int(BGain_new * 256)
return RGain_new_fixed, BGain_new_fixed
3. 说明
| 错误点 | 修正前 | 修正后 |
|---|---|---|
| 中性灰筛选 | 仅单目右图 | 双目中性灰点(左 + 右),且亮度一致(内容无差异) |
| 偏差计算 | 单目 UV-128 | 双目 UV 偏差(右图 - 左图),剔除硬件差异 |
| 公式符号 | 无区分色彩空间 | 按 BT601/BT709 定系数,符号完全匹配 UV 与 RGain/BGain 的映射关系 |
| 输出格式 | 浮点数 | 定点数(ISP 硬件仅支持整数 / 定点数) |
| 干扰排除 | 未排除内容差异 | 加左右目亮度一致性约束,避免场景内容干扰 WB 调整 |
4. 关键执行约束
- ✅ WB 增益调整时机:必须在 ISP 的 "AWB 模块" 之后、"RGB2YUV 模块" 之前执行 ------RGain/BGain 是对 Sensor 原始 RGB 数据的增益,仅作用于后续帧,无法对当前帧已转换的 YUV 回退调整(此前建议 "重新处理" 不符合 ISP 实际);
- ✅ 执行频率:每 10~20 帧调整一次(避免频繁写入 ISP 寄存器导致画面闪烁);
- ✅ 硬件映射:RGain/BGain 在 ISP 中为 16bit 定点数(如 8.8 格式),需将浮点数转换为整数后写入(如 1.0→256,0.8→205)。