在瑞芯微平台上做isp调试,尤其是白平衡调试(AWB),说实话是个“入门容易、做精很难”的活。很早之前,我在RK3568上接一颗OV5695的sensor,第一次拿到RAW图时,整块画面明显偏品红,客户截图发过来第一句话就是“白平衡调一下吧”。我当时第一反应也是AWB,但后来花了一整个下午把BLC、LSC、AWB、CCM、GAMMA逐级分开排查才发现,真正的问题藏在LSC标定数据和镜头光学特性不匹配里,AWB本身其实已经算得很准。这篇文章,我把围绕瑞芯微isp调试里AWB模块的完整经验整理出来,内容包括AWB在ISP pipeline中的工作边界、IQ配置文件里每个关键字段的实际用途、从抓RAW到不同色温全覆盖的完整调参流程,以及几个真实项目里踩过的深坑和排查思路。适合手里拿着RK3568/RK3588/RV1106这类板子、sensor能正常出图但颜色不对、想自己动手调AWB的朋友参考。
1. 开始调试AWB前,先搞清楚ISP链路里谁管颜色、谁管亮度
1.1 读懂ISP pipeline:为什么AWB排在这个位置才算合理
瑞芯微的ISP pipeline,以rkisp/rkaiq这套体系为例,在RAW域上大致是这么一条链:sensor把RAW数据送进来,先做黑电平校正(BLC)把感光底噪和不均匀的暗电流拉掉,再做镜头阴影校正(LSC)把四角亮度差异和偏色拉平,下一步就是AWB,在原始Bayer数据上把R、G、B三个通道的响应差拉回中性。再往后才是去马赛克(demosaic)、色彩校正矩阵(CCM)、gamma、降噪、锐化这些模块。
关键点在于,AWB必须放在demosaic之前处理。因为Bayer数据里每个像素只有一种滤色片,R、G、B三个通道在空间上是错开的。白平衡本质上是在RAW域给R通道和B通道乘一个系数,让灰卡上R/G、B/G的比例落到参考值附近。如果在demosaic和CCM之后再做这件事,那就不叫白平衡增益了,得在RGB空间里对每个像素做矩阵运算,效果差,还容易把CCM调出来的饱和度和色调一起带偏。
我一开始调AWB时踩过最典型的观念坑,就是总觉得“反正显示端也可以拉颜色,图像后端调也行”。实际上瑞芯微这套ISP架构里,sensor标定的wbgain、IQ文件里的r_gain/b_gain、g_gain这些配置,都会直接影响后端CCM和gamma的输入,顺序一旦错位,后面怎么调都别扭。
1.2 画面偏色,问题不一定在AWB:先做模块隔离
很多人拿到偏色图就直接开调AWB,结果调了半天发现边缘又偏了、暗部又紫了。我的习惯是先拍一张固定光源下的灰卡照片,根据偏色的空间分布和亮度特性把所有嫌疑模块排一遍。
| 现象 | 嫌疑模块 | 验证动作 |
|---|---|---|
| 整个画面均匀偏红/蓝,中心和四角一致 | AWB增益/CCM | 抓RAW后算R/G、B/G,对比r_aiq参考点 |
| 四角明显偏暗且偏色,中心正常 | LSC | 换一套LSC标定数据或临时关闭LSC再抓同一场景 |
| 暗部发绿或发紫,高光偏品 | BLC或CCM/gamma | 盖住镜头看黑电平是否接近0;用灰卡全灰阶扫一遍 |
| 只有某个光源下偏色,换光源就正常 | AWB参考点覆盖不足 | 单独切换光源类型验证 |
这个排查表看着简单,但非常管用。比如前面我说那个“画面偏品红”的例子,它其实有个隐藏特征:灰卡在画面中央时颜色接近正常,但把灰卡移到边缘,立刻品红。这种空间分布特征直接指向LSC,而不是AWB。如果你不先做模块隔离,单纯在AWB里加增益,哪怕把r_gain推到顶,边缘还是品的,而且中央也可能会被推绿。
1.3 调试AWB的正确心态:先恢复中性,再谈偏好
关于AWB,我有一个很明确的经验:AWB的职责是“物理还原中性灰”,不是“表达风格”。很多项目喜欢在AWB里强行把画面调得偏暖或者偏冷,比如为了“氛围感”把r_gain故意调高。这种做法在当时的光源下看着很舒服,换个光源就全乱,因为算法会基于错误的参考点去猜色温,结果就是反复横跳。
风格的表达应该交给CCM和gamma去处理。CCM矩阵里包含饱和度、色调偏移这些东西,它可以让红色更红、绿色更绿,并且在不同光源下保持一致性。AWB先把灰还原成灰,CCM再给画面“上色”,两个模块各干各的,才不容易互相牵制。记住这个原则,后面调参的时候你会少走很多弯路。
2. 环境准备:让RK3568的sensor和ISP先稳定出图
2.1 设备树与驱动确认:串口进板子后先查这几样
AWB调试准备工作的第一步,不是去调IQ文件,而是先确认sensor和ISP这条链路已经稳定。我一般通过串口终端登录开发板,先做几个基础确认。
首先是设备树。RK3568设备树里要正确配置sensor节点、CSI D-PHY节点和ISP节点。以OV5695这颗5MP sensor为例,设备树节点大致长这样:
&i2c2 { status = "okay"; ov5695: ov5695@36 { compatible = "ovti,ov5695"; reg = <0x36>; pinctrl-names = "default"; pinctrl-0 = <&ov5695_rst_gpio &ov5695_mclk>; reset-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_LOW>; rockchip,camera-module-index = <0>; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "default"; rockchip,camera-module-lens-name = "default"; port { ov5695_out: endpoint { remote-endpoint = <&mipi_in_ucam0>; ># 查看所有video节点名字,确认sensor和isp节点存在 for v in /sys/class/video4linux/video*; do echo "$v: $(cat $v/name)"; done # 查看media拓扑 media-ctl -d /dev/media0 -p # 确认sensor驱动加载 dmesg | grep ov5695如果这些都正常,再用v4l2-ctl直接抓一帧看看有没有图像。很多偏色问题其实是sensor出图就不完整,比如MIPI lane数配少了、时钟频率不对导致花屏,那些问题在AWB之前就必须解决。
2.2 用v4l2和rkisp抓帧:不同场景下的抓图姿势
sensor和ISP链路稳定之后,接下来就是抓帧。瑞芯微平台上有两种抓帧方式:一种是通过media-ctl把sensor到ISP的链路建立好,然后从ISP的输出节点直接抓;另一种是使用SDK里自带的rkisp_demo这类工具抓帧并保存RAW。
用v4l2的方式大致是:
# 配置media链路,把sensor数据路由到rkisp mainpath media-ctl -d /dev/media0 -r media-ctl -d /dev/media0 -l "ov5695 2-0036:0 -> rkisp-mipi-is0:0 [1]" # 从mainpath抓一帧RAW v4l2-ctl -d /dev/video0 --set-fmt-video=width=2560,height=1920,pixelformat=RGGB --stream-mmap --stream-count=1 --stream-to=frame_raw.raw抓帧时有两点特别重要:第一,AWB调试需要的是RAW图或者至少是ISP统计前的结果,不能直接拿预览图,因为预览图已经过CCM、gamma这些模块,没法反推原始增益。第二,尽量连metadata一起保存,里面带有3A统计信息和当前AWB增益值,调试时可以直接对数据。
如果是在Linux主机上用vscode远程连到开发板做调试,也可以配合gdb直接跟用户态的rk_aiq服务,比如在参数加载阶段抓一下调用栈,看它到底加载的是不是自己预期的那份IQ文件。这个技巧在排查“改了配置但画面没变化”的问题时特别好用。
2.3 上电、光源、图卡:调试AWB的目标环境布置
调试环境这一步,外行人往往不重视,但恰恰是决定调参质量的关键。AWB是和色温强相关的模块,你要让它有据可依,就必须在明确的光源条件下调试。
有条件的,建议用标准光源箱,至少包含D65(6500K日光)、TL84(4000K商场冷白)、A光源(2856K白炽灯)这几种。没有标准灯箱,也可以拿晴天窗边光、白炽灯、荧光灯凑合,但一定要提前记录光源类型,并保证测试期间光源不变化、不闪烁。
图卡方面,一张18%中性灰卡必不可少。用灰卡而不是彩色色卡去调AWB,是因为灰卡在所有色温下都应该是中性的,你只需要对比它在中性灰坐标上的数值就行。调AWB时让灰卡占画面50%以上,确保统计区域里大部分像素都落在灰卡上。同时,最好把sensor固定在手动曝光、手动增益模式,避免AE因为场景亮度变化而自动调节曝光,导致画面统计噪声和亮度权重来回变化,让AWB结果不稳定。
3. IQ配置文件里的AWB字段,逐个说清它是干嘛的
3.1 rkaiq的结构:为什么每个sensor都要配一个IQ文件
瑞芯微的rk_aiq跑在用户空间,每个sensor对应一套IQ配置文件,常见路径在开发板固件的/etc/iqfiles或者/oem/etc/iqfiles下面。文件名一般包含sensor型号和lens信息。这套文件不只是AWB参数,BLC、LSC、CCM、gamma、降噪、锐化全都写在里面,所以你别指望只改一个文件就能解决所有颜色问题。
每个sensor要单独配一套IQ文件,根本原因在于不同sensor的CFA滤色片光谱透过率不一样,同一盏灯照在灰卡上,A相机读出的R/G值是0.50,B相机可能是0.43。这些差异只能靠每个sensor自己的标定数据去补偿。换镜头也一样,LSC和AWB参考点都可能要重新过一遍。
如果你在板子上看到多个IQ文件,比如ov5695_default.xml和ov5695_night.xml,注意看应用启动时到底加载了哪一个。我看过太多人改了白天用的配置,结果应用加载的是夜间配置,画面纹丝不动就以为调的参数没用。
3.2 AWB的核心字段拆解与调参误区
不同SDK版本里,AWB配置字段名会略有差异,我这里用一套通用的结构说明,实际以你板子IQ文件为准:
<awb> <statistic> <window enable="1" x="0" y="0" w="1" h="1"/> </statistic> <algorithm> <mode>auto</mode> <refPoint ct="2800" rg="0.52" bg="0.86"/> <refPoint ct="4000" rg="0.47" bg="0.80"/> <refPoint ct="6500" rg="0.42" bg="0.71"/> </algorithm> <gainLimit> <rMin>0.5</rMin> <rMax>3.0</rMax> <bMin>0.5</bMin> <bMax>3.0</bMax> </gainLimit> </awb>这里从实用角度拆解一下每个字段的作用:
| 字段 | 作用 | 调错之后的典型后果 |
|---|---|---|
| statistic/window | 决定AWB统计哪些区域像素 | 计入高光溢出或天空反光,色温估计被干扰 |
| refPoint | 定义灰卡在某个色温下RAW域的R/G、B/G响应 | 和sensor实际响应不一致时,AWB系统性偏色 |
| gainLimit/rMin等 | 限制增益输出范围,防止极端光源下算法失控 | 上限太小,白炽灯下依然偏黄;下限太大,日光下偏品 |
| mode | 选择自动、锁定、手动等AWB模式 | 切换错误后增益不更新,画面颜色固定在错误色温 |
AWB算法的内部逻辑,本质上是把画面切成很多小块,统计每个小块的R/G、B/G,找出那些接近灰点分布的块,再根据不同色温参考点的位置做加权,估算出当前光源色温。所以refPoint准不准,直接决定算法猜色温猜得准不准。这里最容易犯的错,是从网上抄一份参考值就用,不针对自己的sensor重新标定。即便同一颗sensor型号,不同批次的滤色片透过率也可能有微小差异,照抄的后果就是微偏色,怎么调都摸不着头脑。
3.3 关于增益范围和统计窗口,容易搞混的两处细节
增益范围这玩意看起来很简单,就是上下限嘛,其实里面藏着AWB收敛速度和稳定性的平衡。上限调太大,低照度下算法可能输出一个很高的增益,把本来微弱的色噪声放大成色斑;上限调太小,在2700K的白炽灯下,B通道需要的增益往往接近2.5甚至更高,限制死了偏黄就永远压不回来。我的建议是先依sensor数据手册的响应估算一个粗范围,再通过实测不同光源下“固定增益”抓RAW的结果去修正,不要凭感觉设一个数。
统计窗口的坑则更隐蔽。默认情况下AWB统计会做整个画幅的像素,但实际场景里往往会存在高光点、镜面反射、或者直射的太阳区域。这些区域在RAW域上的R/G、B/G值严重偏离灰线,会把统计结果往错误方向拉。尤其是有LED屏幕或者金属反光的监控场景,AWB疯狂漂移多半就是统计窗口里混入了不该参与统计的像素。处理方式就是把统计window裁剪到画面中央区域,或者至少把已知的高光反射区域排除掉。
4. 白平衡调试的实操流水线:从原始RAW到不同色温全覆盖
4.1 用灰卡做基准:计算当前增益离目标差多少
实操流程的第一步,是把AWB增益固定为1:1:1,也就是让R、G、B三个通道都不做增益补偿,直接抓一张RAW。然后在D65光源下放灰卡,让灰卡占满画面中央,统计灰卡区域的Bayer均值。
举个例子,假设我抓回来RAW,统计灰卡区域得到R=92、G=200、B=156(8bit数值)。那么当前RAW域的响应比例是:
- R/G = 92 / 200 = 0.46
- B/G = 156 / 200 = 0.78
再看IQ文件里D65色温的refPoint。如果写的是rg=0.46、bg=0.78,那就完美匹配,AWB在D65下应该输出近似1:1的增益。如果测出来是R/G=0.55、B/G=0.65,说明R通道响应高了,B通道响应低了,要让灰卡恢复中性,就需要把R通道增益压低、B通道增益抬高。
计算公式很简单,以G为基准:
- r_gain = 1 / R_G(如果用RAW响应比例的话)
- b_gain = 1 / B_G
比如R/G=0.55,那需要的r_gain就是1/0.55≈1.82,b_gain是1/0.65≈1.54。这个数值不是让你直接塞进去,而是作为参考点修正的依据。这个计算逻辑在每一步调试里都会用到,建议先彻底搞懂。
4.2 推参考点还是推增益曲线?
同一颗sensor在不同色温下,RAW域的R/G、B/G响应是连续变化的。所以正确做法是采集3-5个色温点,把每一点的实测响应作为refPoint填进IQ文件,算法在任意色温下都通过插值得到参考值。这比单独调某一条增益曲线更稳定、更合理。
我遇到很多新手,喜欢直接去改AWB输出端的“白平衡增益表”,也就是让算法在某个色温下固定输出一个增益值。这种做法的坏处是:你只修了这一个点的显示结果,但相邻色温下算法插值时会把突变带进去,导致光照稍微一变颜色就跳一下。更麻烦的是,你很可能在掩盖这个色温下CCM或者LSC的真实问题。
所以我的调试顺序是:先固定增益抓RAW确定sensor真实响应,用实测值更新refPoint;如果refPoint已经和实测一致但AWB输出仍然偏色,才考虑去检查下游CCM。记住,refPoint描述的是“传感器的事实”,增益表描述的是“算法的输出”,事实不能去迁就算法输出。
4.3 不同光源下的巡回验证与记录表
单个色温调准不算完,AWB必须到多光源下去回归验证。常规三光源是D65(6500K)、TL84(4000K)、A光源(2856K)。每换一个光源,重复上一步操作:固定增益抓RAW、测灰卡响应、比对refPoint、修改配置、重新运行确认。
我自己的记录表大概是下面这样:
| 光源 | 目标色温 | 灰卡R/G实测 | 灰卡B/G实测 | refPoint修正值 | AWB收敛时间 | 备注 |
|---|---|---|---|---|---|---|
| D65 | 6500K | 0.46 | 0.78 | 0.46/0.78 | 1.2s | 正常 |
| TL84 | 4000K | 0.49 | 0.80 | 0.49/0.80 | 1.5s | 正常 |
| A光源 | 2856K | 0.53 | 0.87 | 0.53/0.87 | 2.0s | 略慢,待优化 |
如果某个光源下AWB收敛时间明显偏长,多半是相邻色温参考点的差值设置过大,导致算法在判断光照到底落在哪个区间时犹豫不决。可以考虑在两个色温之间再插一个中间参考点,让过渡更平滑。
这里还要特别提醒一个场景:混合光源。比如画面一半是从窗户进来的日光,一半是室内白炽灯,AWB永远无法同时满足两个光源下的中性。这时候你要根据项目实际需求做取舍,是保画面主体入射光,还是保全场平均不偏得离谱。瑞芯微的AIQ里一般也有混合光源处理策略,但不管选哪个策略,你都必须明确告诉客户“这种场景没有完美解”,而不是反复去调参数期望魔法发生。
5. 真实项目里踩过的AWB深坑,附完整排查思路
5.1 坑一:边缘偏色,AWB显示已收敛但画面仍难看
现象是:灰卡在画面中央时,AWB统计显示已经收敛,R/G、B/G都在参考点附近,但肉眼看整个画面四角还是明显偏红偏紫。这个问题在产品整机测试时最容易暴露。
我当时的排查链路是这样的:先看AWB统计窗口,默认是全画幅,平均下来灰卡中央数值被边缘带偏,导致算法以为已经中性了。但单看边缘色块,它的Bayer响应统计和中央差别极大。这说明问题的根源不在AWB,而在于LSC没有把镜头本身的色彩阴影打平。重新跑了LSC标定,再用新参数去抓同一场景,四角偏色基本消失,AWB的统计也稳定了。
这个案例再次验证了模块隔离的重要性。如果一上来就把AWB统计窗口缩到中间,让中心参考点收敛得“更准”,其实是把LSC的问题掩盖了,恢复了LSC之后AWB参数反而不用大动。
5.2 坑二:冷暖光切换时AWB来回横跳、收敛慢
现象是:在D65光源下拍完,切到白炽灯,AWB用了四五秒才稳定,期间画面在偏黄和偏蓝之间来回大幅度摆动,监控视频录下来像抽风一样。
排查时我先看了增益日志,发现单帧增益步进特别大,第一帧还是1.1,第二帧直接跳到2.3,第三帧又掉回1.4,整个系统在震荡。这个问题的根子有两个:一是帧间滤波没生效,AWB对每一帧统计结果过于信任;二是D65和2800K参考点之间隔着一段,没有合适的中间值,算法在“到底是哪种光”之间反复横跳。
处理方案也很直接:把帧间滤波系数调大,让单帧统计结果对最终增益的影响降低;再在4000K左右补一个参考点,让色温估计曲线过渡平滑。修完之后收敛时间压到了1.5秒以内,没有再出现抖动。这类振荡问题一定要看统计日志和增益日志,只看预览画面很难分清到底是算法问题还是光源本身波动。
5.3 坑三:低照度高增益下AWB误判严重
现象是:晚上光线很暗,环境大概几百勒克斯以下,AWB把原本6500K的灯下场景误判成3000K,画面被补偿得偏蓝,人脸色发青。
这个问题的本质在于低照度下sensor噪声变大,尤其高增益做上去之后,噪声在色度统计里被当成有效信号。灰点检测算法本来应该排除那些亮度太低的块,但默认阈值往往按正常光照设计,低亮度块的R/G、B/G分布发散得很厉害,AWB就会在色温轴上乱猜。
我的处理是在统计端增加亮度下限阈值,把低信噪比的块从灰点候选中剔除;同时把灰点检测的色度置信区间稍微放宽,避免过度依赖噪声大的区域。还有一个联动点:查看一下低照度时AE是不是把增益推到很高,如果是,建议限制sensor最大模拟增益,把亮度不足的部分交给补光或者接受噪点,而不是让AWB在这种条件下硬猜。低光AWB永远没有完美解,关键在于设一个“算不准就保持上次值”的阻尼逻辑,而不是频繁跳变。
5.4 坑四:预览和抓帧颜色不一致,截图都查不出根源
现象是:在应用界面上看预览画面颜色正常,但用抓帧工具存出来的图偏色,把两张图放一起对比怎么也找不到规律。
这个问题我排查了很久,后来发现预览链路和抓帧链路走的不是同一套IQ配置。预览模式经过rk_aiq完整处理后输出到显示,抓帧模式在某些SDK版本里直接走了bypass,跳过了一部分3A统计或者用了不同的demosaic参数。还有个可能是抓帧时分辨率不同,ISP对不同分辨率的处理路径有差异,导致CCM和gamma的查找表也不一样。
遇到这类问题,别再对着图猜了。先确认你抓的帧是不是从同一个ISP输出节点出来的,确认抓帧时有没有带metadata。把预览和抓帧的metadata放在一起对比,看里面的wbgain、ccm矩阵、gamma表是否一致,差异在哪里基本就一目了然。这个排查思路,几乎可以复制到所有“显示和抓帧不一致”的场景。
6. 把调试结果固化进产线:AWB从开发板走向量产的注意事项
6.1 IQ文件的管理与打包路径
AWB参数在开发板上调好之后,下一步是把它固化到固件里。瑞芯微平台通常的做法,是把这套IQ文件放到系统镜像的固定目录下,应用启动时去扫描加载。为了避免开发和生产脱节,我强烈建议对IQ文件做版本管理,文件名里带上映像传感器型号、镜头型号、日期和修改人。等到产线反馈颜色问题,你能第一时间知道这批机器刷的是哪一版配置。
启动加载IQ文件的逻辑也要确认清楚。有些应用通过命令行参数指定路径,有些从环境变量读,还有些写死在代码里。如果你改了文件但应用还是加载旧配置,多半是加载路径写死到了另一个目录。调试阶段就在加载代码里加一行日志,打印实际加载的文件路径,能省掉后面无数排查时间。
6.2 产线标定时如何设计光源工位
产线标定AWB,最怕的是光源不标准。普通日光灯管色温漂移很大,显色指数也低,拍出来的灰卡本身就不灰,标出来的参数自然对不上。
我见过比较靠谱的产线工位是这样设计的:用一个封闭或半封闭的标定箱,内部用高显色指数光源,至少CRI 95以上,D65和TL84各一组,光源到标定板距离固定,标定相机到标定板距离固定,所有几何条件不随人员变动。标定工位最好和环境光隔离,或者安排在暗室。
标定顺序上,我建议先做LSC标定,再做AWB标定,最后人工目视确认色彩表现。LSC标定没做,AWB的统计会被边缘阴影干扰,先做哪个都不如先做LSC。另一个经验是,产线标定用的灰卡要和开发调试用的同一批次,灰卡本身用旧了、脏了,反光特性变了,标出来的参数也会慢慢漂移。
6.3 批次一致性与后续线上抽检
不同批次的sensor和镜头,光学特性会有细微差异。所以量产阶段别只标一台定版,要在同一批次里抽5到10台机器做灰卡测试,记录每台的R/G、B/G和wbgain数据,看看离散度有多大。如果离散度明显超过预期,优先查镜头批次,因为镜头的光谱透过率差异通常比sensor批次更明显。
线上抽检环节,可以让产线工位拍一张灰卡,脚本自动计算画面中央的R/G、B/G,设置一个容忍范围,超出范围的报警拦截。这个自动化脚本不复杂,但对控制批次一致性非常有效。千万注意,产线发现问题时不要图快直接调产线机器的AWB参数,正确做法是把当批的RAW数据拿回实验室,统一分析之后在IQ文件版本上修,再重新下发。
我在实际项目里体会到,AWB调试的心态和流程比参数本身重要得多。只要你愿意先做模块隔离、固定光源、用灰卡做基准、按不同色温巡回验证,哪怕你的板子不是瑞芯微,这套方法论也能直接用。最忌讳的就是拿到偏色图就凭感觉甩增益,那样大概率会把AWB、CCM、LSC的问题搅成一团,后面改到崩溃。
最后再分享一个小技巧:每次修改完AWB配置,把抓的RAW图、对应IQ文件版本、光源条件放在同一个目录存好,同一光照条件测三次确认结果一致再收口。之后无论客户反馈问题还是产线要排查,你都能在十分钟内找到对应的测试基线,少走很多弯路。