第二章:3A算法基础理论——AE、AWB、AF的核心原理

各位同学,欢迎来到第二章。这一章我们不讲代码,也不谈平台移植,先把3A算法的“根”扎牢。

自动曝光(AE)、自动白平衡(AWB)、自动对焦(AF),这三个模块在ISP(图像信号处理)流水线里是铁三角。我见过不少工程师,调参调得飞起,但问起测光原理、色温估计、对焦检测的区别,反而说不清楚。嗯,这其实很危险——算法移植时,一旦底层逻辑变了,你连问题出在哪都找不到。

所以今天,我们就把这三兄弟的底裤扒干净。

3A算法核心知识体系 3A算法核心知识体系 AE 自动曝光 测光模式 全局测光 / 中央重点 点测光 / 多区测光 目标亮度 18% 灰 / 直方图均衡 AWB 自动白平衡 色温估计 灰世界 / 完美反射 色温曲线映射 颜色校正 CCM 矩阵 / 增益调整 AF 自动对焦 对比度检测 Sobel / Laplacian 爬山搜索算法 相位检测 PDAF 像素 / 视差 核心目标:让摄像头在任何场景下都能输出“人眼看起来舒服”的图像 AE 控制亮度 → AWB 还原色彩 → AF 保证清晰

2.1 自动曝光(AE):测光原理与目标亮度

AE 要解决什么问题?说白了就一句话:让图像不暗不亮,细节都在。但现实场景的亮度范围动辄 100dB 以上,而 sensor 的动态范围可能只有 60-70dB。怎么取舍?这就是测光的艺术。

2.1.1 测光模式

我个人习惯把测光模式分成四类,你在不同场景下得选对武器:

测光模式 原理简述 适用场景 我踩过的坑
全局测光 全图像素亮度取平均 光照均匀的户外 逆光时人脸全黑
中央重点 中心区域权重更高 人像、会议 主体不在中心就翻车
点测光 只取画面 1%-5% 区域 舞台、逆光特写 对焦点选错直接过曝
多区测光 画面分区独立测光+AI融合 复杂光场景 算力开销大,低端芯片扛不住
我的经验:在嵌入式平台上,我建议优先用中央重点测光 + 人脸检测的混合方案。既保证主体曝光,又不会像多区测光那样吃掉太多 CPU 周期。我在海思 3516 上就这么干过,效果很稳。

2.1.2 目标亮度与 18% 灰

你想想看,为什么相机拍一张白纸和一张黑纸,出来的亮度不一样?因为 AE 的参考标准是 18% 中性灰。这是人眼感知的中等亮度点,也是整个曝光控制的锚点。

实际算法里,我们会把测光得到的亮度值映射到目标亮度区间。比如:

// 伪代码:AE 目标亮度调整
target_luminance = 128;  // 8bit 图像,18% 灰对应约 128
current_luminance = get_avg_luminance(frame);
gain = target_luminance / (current_luminance + 1e-6);
// 限制增益范围,防止震荡
gain = clamp(gain, 0.5, 4.0);
apply_exposure_gain(gain);
注意:千万不要让 AE 收敛太快。我曾经在项目中把增益步长设得太大,结果画面像呼吸一样忽明忽暗,用户直接投诉。建议每次调整不超过 0.3dB,配合死区(dead zone)防止抖动。

2.2 自动白平衡(AWB):色温估计与颜色校正

AWB 的核心任务,就是让白色物体在任何色温下都看起来是白的。听起来简单?其实不然。人眼有色彩恒常性,但 sensor 没有——它在日光灯下发绿,在白炽灯下发黄。

2.2.1 色温估计方法

我做过好几个 AWB 方案,最常用的就两种:

  1. 灰世界法(Gray World):假设场景中所有颜色的平均是灰色。如果 R/G/B 均值不相等,就调整增益让它们相等。
  2. 完美反射法(Perfect Reflector):找到画面中最亮的像素,假设它是白色,然后以此为基准校正。

但说实话,这两种方法单独用都有问题。灰世界法遇到大面积单色场景(比如蓝天、绿草地)会翻车;完美反射法如果场景里没有真正的白色物体,也会偏色。

我的做法:把两种方法加权融合。先用灰世界法算一个基础色温,再用完美反射法检测高光区域做修正。权重根据场景动态调整——比如检测到大量绿色,就降低灰世界法的权重。这套方案我在高通骁龙平台上跑过,色温误差控制在 200K 以内。

2.2.2 颜色校正矩阵(CCM)

色温估计完了,接下来就是校正。校正不是简单调 RGB 增益,而是要用一个 3x3 的矩阵:

// CCM 校正示例
[R']   [ 1.8  -0.5  -0.3 ] [R]
[G'] = [-0.2   1.6  -0.4 ] [G]
[B']   [-0.1  -0.3   1.4 ] [B]

这个矩阵的作用是消除 sensor 的串扰和色偏。不同色温下,CCM 矩阵也不同。我一般会准备 5-8 组 CCM,对应 2500K、4000K、5500K、6500K、8000K 等典型色温点,然后线性插值。

色温点 场景举例 R 增益 G 增益 B 增益
2500K 白炽灯 1.8 1.0 1.2
5500K 日光 1.0 1.0 1.0
8000K 阴天 1.1 1.0 1.6
避坑指南:我曾经在移植 AWB 到新 sensor 时,直接用了上一颗 sensor 的 CCM 矩阵,结果颜色偏紫得一塌糊涂。每个 sensor 的 CFA 排列和光谱响应都不一样,CCM 必须重新标定。别偷懒。

2.3 自动对焦(AF):对比度检测与相位检测

AF 的目标很直接——让图像最清晰。但怎么定义“清晰”?这就引出了两种主流方案。

2.3.1 对比度检测(CDAF)

CDAF 的原理很简单:图像越清晰,边缘越锐利,相邻像素的差异越大。我们用 Sobel 或 Laplacian 算子计算图像的梯度值,然后找梯度最大的镜头位置。

// CDAF 清晰度评价函数(Tenengrad)
float calc_sharpness(uint8_t* frame, int w, int h) {
    float sum = 0;
    for (int y = 1; y < h-1; y++) {
        for (int x = 1; x < w-1; x++) {
            int gx = frame[(y-1)*w+x+1] + 2*frame[y*w+x+1] + frame[(y+1)*w+x+1]
                   - frame[(y-1)*w+x-1] - 2*frame[y*w+x-1] - frame[(y+1)*w+x-1];
            int gy = frame[(y+1)*w+x-1] + 2*frame[(y+1)*w+x] + frame[(y+1)*w+x+1]
                   - frame[(y-1)*w+x-1] - 2*frame[(y-1)*w+x] - frame[(y-1)*w+x+1];
            sum += gx*gx + gy*gy;
        }
    }
    return sum / (w * h);
}

CDAF 的优点是精度高,但缺点也很明显——慢。它需要镜头走完整个行程才能找到峰值,俗称“拉风箱”。

2.3.2 相位检测(PDAF)

PDAF 就聪明多了。它在 sensor 上埋了一排特殊的相位检测像素,左右各看一半画面。如果左右图像对齐,说明合焦;如果错位,就知道该往哪个方向推镜头。

相位差与离焦量的关系:

// PDAF 相位差计算
phase_diff = left_pixel - right_pixel;
// 正数表示前焦,负数表示后焦
lens_step = phase_diff * calibration_factor;
性能对比:CDAF 精度可达 1 个像素级别,但需要 20-30 帧才能收敛;PDAF 只需 1-2 帧就能给出方向,但精度受限于相位像素的密度。我现在的做法是 PDAF 粗调 + CDAF 精调,又快又准。

2.3.3 混合对焦策略

在实际项目中,我很少只用一种方案。下面这个表格总结了不同场景下的选择:

场景 推荐方案 原因
静态拍照 CDAF 精度优先,不差那几百毫秒
视频追焦 PDAF + CDAF 既要速度又要精度
低光环境 PDAF CDAF 在暗光下梯度太弱,容易误判
快速抓拍 PDAF 一帧定焦,不拖泥带水
一个小技巧:在移植 PDAF 到新平台时,一定要重新标定 calibration_factor。不同 sensor 的微透镜阵列和像素间距不同,直接用旧参数会导致对焦不准。我吃过这个亏,花了三天才定位到问题。

好了,这一章的内容就是这些。AE、AWB、AF 三个模块的原理,是后续所有移植和优化工作的基础。你把这些吃透了,后面讲平台适配、算力优化、流水线并行时,才能跟得上节奏。