文章目录
-
- 1.AWB算法原理介绍
- 2.AWB算法的代码
- [3.AWB 测试代码](#3.AWB 测试代码)
-
- ['GRBG' bayer pattern 测试代码](#'GRBG' bayer pattern 测试代码)
- [R 通道单独拉gain测试代码](#R 通道单独拉gain测试代码)
- [4.实际平台AWB tuning是怎么做的](#4.实际平台AWB tuning是怎么做的)
-
- [如何计算AWB gain表](#如何计算AWB gain表)
- [AWB 增益是如何应用的?](#AWB 增益是如何应用的?)
-
- [实际案例推演:D65 光源下的红苹果](#实际案例推演:D65 光源下的红苹果)
1.AWB算法原理介绍
不同光源(日光、钨丝灯、荧光灯)的色温不同,导致相机捕获的图像存在色偏。AWB 通过对各颜色通道乘以增益系数,使白色物体在输出图像中呈现为白色。
openISP的AWB模块实现的是增益应用阶段(Gain Apply),增益值由上游的白平衡算法(如灰世界算法、完美反射算法)预先计算好,这里只做乘法。
数学公式
R_out = R_in × r_gain
Gr_out = Gr_in × gr_gain
Gb_out = Gb_in × gb_gain
B_out = B_in × b_gain
Gr 和 Gb 分别有独立增益,用于校正镜头渐晕(Lens Shading)造成的绿色通道不均匀。
2.AWB算法的代码
这里只是简单的根据bayer patter的格式,分别应用不同通道的gain, 这里我们需要提前知道这个gain表,关于如何tuning出gain表,在文章最后有介绍. 此时算法只是简单的对各通道加权.
python
class WBGC:
'Auto White Balance Gain Control'
def __init__(self, img, parameter, bayer_pattern, clip):
self.img = img
self.parameter = parameter
self.bayer_pattern = bayer_pattern
self.clip = clip
def clipping(self):
np.clip(self.img, 0, self.clip, out=self.img)
return self.img
def execute(self):
r_gain = self.parameter[0]
gr_gain = self.parameter[1]
gb_gain = self.parameter[2]
b_gain = self.parameter[3]
raw_h = self.img.shape[0]
raw_w = self.img.shape[1]
awb_img = np.empty((raw_h, raw_w), np.int16)
if self.bayer_pattern == 'rggb':
r = self.img[::2, ::2] * r_gain
b = self.img[1::2, 1::2] * b_gain
gr = self.img[::2, 1::2] * gr_gain
gb = self.img[1::2, ::2] * gb_gain
awb_img[::2, ::2] = r
awb_img[::2, 1::2] = gr
awb_img[1::2, ::2] = gb
awb_img[1::2, 1::2] = b
elif self.bayer_pattern == 'bggr':
b = self.img[::2, ::2] * b_gain
r = self.img[1::2, 1::2] * r_gain
gb = self.img[::2, 1::2] * gb_gain
gr = self.img[1::2, ::2] * gr_gain
awb_img[::2, ::2] = b
awb_img[::2, 1::2] = gb
awb_img[1::2, ::2] = gr
awb_img[1::2, 1::2] = r
elif self.bayer_pattern == 'gbrg':
b = self.img[::2, 1::2] * b_gain
r = self.img[1::2, ::2] * r_gain
gb = self.img[::2, ::2] * gb_gain
gr = self.img[1::2, 1::2] * gr_gain
awb_img[::2, ::2] = gb
awb_img[::2, 1::2] = b
awb_img[1::2, ::2] = r
awb_img[1::2, 1::2] = gr
elif self.bayer_pattern == 'grbg':
r = self.img[::2, 1::2] * r_gain
b = self.img[1::2, ::2] * b_gain
gr = self.img[::2, ::2] * gr_gain
gb = self.img[1::2, 1::2] * gb_gain
awb_img[::2, ::2] = gr
awb_img[::2, 1::2] = r
awb_img[1::2, ::2] = b
awb_img[1::2, 1::2] = gb
self.img = awb_img
return self.clipping()
3.AWB 测试代码
'GRBG' bayer pattern 测试代码
测试代码创建8x8的图像,其中R和B通道的值分别为100和200.其中3.0, 1.0, 1.0, 1.0,这个参数分别为R,Gr,Gb,B通道的增益.
python
def test_bayer_pattern_grbg(self):
"""grbg 模式:Gr 在偶行偶列,R 在偶行奇列。"""
img = np.zeros((8, 8), dtype=np.uint16)
img[0::2, 1::2] = 100 # R 位置
img[1::2, 0::2] = 200 # B 位置
awb = WBGC(img.copy(), [3.0, 1.0, 1.0, 1.0], 'grbg', clip=2000)
out = awb.execute()
show_bayer_images('grbg', img, out, "left", "right-grgb-bayer")
#self.assertEqual(int(out[0, 1]), 300) # R×3
#self.assertEqual(int(out[1, 0]), 200) # B×1
- 测试效果
因为代码中的R通道的gain较大,我们可以知道,图像肯定是偏红的.

R 通道单独拉gain测试代码
生成一张8x8,pattern为RggB, 各通道值均为100的灰度图. 其中2.0, 1.0, 1.0, 1.0,这个参数分别为R,Gr,Gb,B通道的增益.
python
def test_r_gain_applied(self):
"""r_gain=2 时,R 通道(rggb 偶行偶列)值应翻倍。"""
img = make_bayer_rggb(8, 8, r_val=100, g_val=100, b_val=100)
awb = WBGC(img.copy().astype(np.uint16), [2.0, 1.0, 1.0, 1.0], 'rggb', clip=1023)
out = awb.execute()
show_bayer_images('rggb', img, out, "left", "right-rggb-AWB(r_gain)")
- 效果图
同理R通道相对于其它通道打了1被,可以理解图像偏红的.

4.实际平台AWB tuning是怎么做的
Tuning人员需要在标准灯箱中,使用不同色温的光源(如 D75、D65、D50、CW、TL84、A、H 等七种光源)拍摄 18% 灰卡 或24色色卡 。通过计算每张图片颜色的 R/G 和 B/G 比值,将这些数据点在坐标轴上作为参考点(锚点)。这些参考点用于帮助算法估计当前场景的相关色温(CCT)。
我们知道灰色的RGB各分量都是一样的,一般我们以G通道的值来作为基准,来计算R和B通道相对G通道的增益值.
如何计算AWB gain表
在灯箱环境下,拍摄灰卡图像,然后使用tuning工具计算gain表, 为了降低运算量,工具一般不会给每个像素点计算一个gain,而是在 RAW 域会将整张图像切分为固定大小的网格区块(Block)。工具只对这些区块进行统计,而不是逐像素处理。
- 高通平台:通常支持将图像划分为如 17×13 的网格(接近 4:3 比例),每个区块负责采样并统计其对应区域的亮度与色彩信息。
- 联发科(MTK)平台:AWB 统计值通常是记录每个 Block 输出中心像素的 R/G/B 值,用于后续的色温估计。
- 通用做法:将拜尔(Bayer)图像分离为 R、GR、GB、B 通道,根据指定尺寸划分区块,并计算每个区块的平均 R、G、B 值。
计算gain的方式有2种
-
全局增益 (Global Gain):在传统的灰度世界假设(Gray World)或完美反射体算法中,算法会汇总所有有效区块的 R/G 和 B/G 比例,计算出一组全局的 。这组增益随后会应用到整幅图像的所有像素上。
这种情况我的理解是,在进行camera sensor选型的时候,模组厂会提供一组golden模组, 这时候需要tuning人员根据不同光源测算出golden模组的R_gain,G_gain(1.0),B_gain, 然后研发人员会将此值写入sensor OTP区域,以供sensor一开始能输出一个较好的图片.
-
ROI 约束白平衡(ROI-based WB):在复杂场景下,算法会选定具有已知色彩特性的局部区域(如中性灰区域、人脸肤色区域,或用户手动点击的区域)作为 ROI。算法仅对这些 ROI 内的区块进行统计分析,计算出增益后,再将其作为基准应用到整幅图像,从而避免大面积单色背景导致的偏色。
这里比如灰卡拍出来的图像是8x8的,且我们的**ROI是4x4的,**那么分别计算每个区域的平局R,G,B值,
然后根据如下公式计算.
R_gain = R/G
G_gain = 1.0
B_gain = B/G
这样得到的是一个2x2的gain表,

AWB 增益是如何应用的?
AWB 的本质是改变 RGB 感光电路信号的放大比例。在 Bayer 域(RAW 数据阶段),算法会对图像中的每一个像素点,根据其所在的颜色通道,乘以对应的增益系数。
假设在 D65 光源下,通过灰卡计算出的 AWB 增益为 R_gain, G_gain( 通常设置为1.0),B_gain,对于图像中的任意一个像素点(无论是灰卡还是红苹果),其校正后的像素值( R',G',B')计算公式为:
>R′ = R × R_gain
G' = G x G_gain
B' = B x B_gain
实际案例推演:D65 光源下的红苹果
在 D65(高色温,偏蓝)光源下,环境光中蓝光成分较多,红光成分较少。
假设通过灰卡标定,ISP 计算出的增益为: R_gain = 1.5, G_gain = 1.0, B_gain = 0.8.
-
对于灰卡(中性色):
原始 RGB 值为 (100, 100, 100)。
应用增益后:R' = 100 x 1.5 = 150
G' = 100 x 1.0 = 100
B' = 100 x 0.8 = 80.
此时 R:G:B 的比例被拉平,灰卡成功还原为白色/灰色。
-
对于红苹果(彩色):
在 D65 光源下,红苹果吸收了大部分蓝光和绿光,反射了红光。假设传感器捕捉到的原始 RGB 值为 (120, 40, 30)。
应用同样的增益后:R' = 120 x 1.5 = 180
G' = 40 x 1.0 = 40
B' = 30 x 0.8 = 24
结果分析:校正后的像素值为 (180, 40, 24)。虽然绝对值变大了,但 R:G:B 的相对比例(色彩属性)被完美保留了。因此,红苹果依然呈现鲜艳的红色,而不会变成白色。