4. 曝光控制基础:曝光三角、直方图与自动曝光算法

曝光控制,说白了就是决定「多少光进到传感器里」。我刚开始做图像处理时,总觉得曝光是相机的事,跟我算法工程师没关系。直到有一次在强光下做车牌识别,过曝导致车牌号全白——嗯,从那以后我再也不敢轻视曝光控制了。

4.1 曝光三角:光圈、快门、ISO

这三个参数共同决定最终图像的亮度。它们的关系很简单:曝光量 = 光圈 × 快门 × ISO。但每个参数的影响远不止亮度这么简单。

参数 物理含义 对图像的影响 典型值范围
光圈 (Aperture) 镜头通光孔径大小 控制进光量 + 景深 f/1.4 ~ f/22
快门 (Shutter) 传感器感光时间 控制进光量 + 运动模糊 1/8000s ~ 30s
ISO 传感器信号放大增益 控制亮度 + 噪声水平 100 ~ 12800

核心原则:优先调光圈和快门,ISO 是最后手段。因为 ISO 本质是放大信号,同时也会放大噪声。

4.1.1 光圈:不只是通光量

光圈值用 f-number 表示,比如 f/2.8。数值越小,光圈越大,进光越多。但有个坑——光圈越大,景深越浅。

我在做文档扫描 App 时遇到过:用 f/1.8 大光圈拍文档,中间清晰,边缘模糊。用户投诉说「拍出来字是花的」。后来我建议固定到 f/5.6 ~ f/8,问题就解决了。

避坑指南:场景自适应调参时,如果检测到文本/条码场景,建议强制收小光圈(f/5.6 以上),保证全画面清晰度。

4.1.2 快门:冻结运动还是记录轨迹

快门速度决定了运动物体在画面中的表现。1/1000s 可以冻结飞鸟,1/30s 就会拍出拖影。

我个人的经验是:手持拍摄的安全快门是 1/焦距。比如用 50mm 镜头,快门至少 1/50s。低于这个值,手抖就会导致模糊。

但自动曝光算法不会考虑「手抖」——它只算亮度。所以很多手机在暗光下会降到 1/10s,结果拍出来全是糊的。这就是为什么 OIS(光学防抖)在暗光下那么重要。

4.1.3 ISO:噪声的源头

ISO 是传感器信号的放大倍数。ISO 100 是原生感光度,噪声最小。ISO 3200 以上,暗部就会出现明显的彩色噪点。

我记得有一次做夜景模式,算法把 ISO 拉到 6400,结果图像全是「雪花」。后来我们改用多帧合成 + 低 ISO,效果反而更好。

注意:ISO 不是物理进光量,而是电子放大。放大信号的同时,也放大了传感器本身的暗电流噪声和读出噪声。高 ISO 图像后期降噪会损失细节。

4.2 直方图分析:曝光质量的「体检报告」

直方图是图像亮度分布的统计图。横轴是亮度(0~255),纵轴是像素数量。我每次拿到一张图,第一件事就是看直方图——它比人眼更客观。

4.2.1 直方图的三种典型形态

  • 正常曝光:直方图分布均匀,左右两端都有少量像素,中间饱满。
  • 过曝:像素集中在右侧(高亮区),右端「撞墙」——细节丢失。
  • 欠曝:像素集中在左侧(暗区),左端「撞墙」——暗部死黑。

你想想看,如果直方图两端都撞墙,说明这张图动态范围已经超出传感器能力了。这时候单纯调曝光没用,得用 HDR 或多帧合成。

4.2.2 直方图在自动曝光中的应用

自动曝光算法会实时计算直方图的统计特征:

// 伪代码:基于直方图的曝光评估
float computeExposureScore(Histogram hist) {
    float mean = hist.mean();          // 平均亮度
    float std  = hist.stddev();        // 标准差
    float clipLeft  = hist.cdf(10);    // 暗部裁剪比例
    float clipRight = hist.cdf(245);   // 亮部裁剪比例

    // 目标:平均亮度在 100~150,裁剪比例 < 1%
    if (mean < 100) return UNDER_EXPOSED;
    if (mean > 150) return OVER_EXPOSED;
    if (clipLeft > 0.01 || clipRight > 0.01) return CLIPPING;
    return GOOD;
}

关键指标:自动曝光算法通常以「平均亮度落在 100~150 区间」为目标。但场景自适应系统会根据场景类型调整这个目标值——比如夜景可以偏暗(目标 80),雪景可以偏亮(目标 180)。

4.3 自动曝光算法原理

自动曝光(AE)本质上是一个闭环控制系统。传感器测量当前亮度,算法计算偏差,然后调整曝光参数,直到亮度达到目标值。

4.3.1 经典 AE 算法:爬山法

爬山法是最基础的 AE 算法。它像爬山一样,一步步调整参数,直到「山顶」(目标亮度)。

  1. 测量当前图像的平均亮度 Y_cur
  2. 计算与目标亮度 Y_target 的差值 ΔY = Y_target - Y_cur
  3. 根据 ΔY 调整曝光时间或增益
  4. 重复 1~3,直到 |ΔY| < 阈值

但爬山法有个问题——容易在明暗交替场景中震荡。比如你从室内走到室外,亮度突变,算法会来回调整,画面一闪一闪的。

4.3.2 改进算法:加权区域测光

为了解决全局平均亮度不准确的问题,业界引入了区域加权:

测光模式 权重分布 适用场景
中央重点测光 画面中央 60% 权重 人像、主体在中央
点测光 仅中心 2~5% 区域 逆光、舞台
矩阵/评价测光 全画面分区加权 通用场景

我个人习惯用矩阵测光 + 人脸检测加权。如果画面中检测到人脸,人脸区域的权重提升到 60% 以上。这样即使背景很亮,人脸也不会欠曝。

4.3.3 现代 AE 算法:场景自适应曝光

这是本课程的核心内容之一。场景自适应 AE 不再是简单的「亮度闭环」,而是结合场景理解:

// 场景自适应 AE 决策流程
SceneType detectScene(Image frame) {
    if (hasFace(frame)) return PORTRAIT;
    if (isNight(frame)) return NIGHT;
    if (isBacklit(frame)) return BACKLIT;
    return GENERAL;
}

ExposureParams computeAE(SceneType scene, Histogram hist) {
    switch(scene) {
        case PORTRAIT:
            targetBrightness = 130;  // 人脸偏亮
            maxISO = 800;           // 控制噪声
            break;
        case NIGHT:
            targetBrightness = 80;   // 保留暗部氛围
            maxShutter = 1/15;      // 防手抖
            break;
        case BACKLIT:
            targetBrightness = 120;  // 提亮主体
            enableHDR = true;       // 开启 HDR
            break;
        default:
            targetBrightness = 110;
    }
    // ... 执行 PID 控制
}

经验之谈:场景自适应 AE 的关键不是算法多复杂,而是场景分类的准确率。我见过很多方案,场景分类准确率只有 70%,结果 AE 反而比通用算法更差。先做好场景分类,再优化 AE 参数。

4.4 曝光控制知识体系

下面这张图总结了本章的核心知识结构:

曝光控制知识体系 曝光控制 光圈 (Aperture) 快门 (Shutter) ISO (增益) 影响:进光量 + 景深 影响:进光量 + 运动模糊 影响:亮度 + 噪声水平 直方图分析 自动曝光算法 过曝/欠曝检测 动态范围评估 爬山法/PID控制 场景自适应AE 目标:亮度适中 + 细节保留 + 噪声可控

4.5 本章小结

曝光控制是图像质量的基石。光圈、快门、ISO 三者相互制约,没有「万能参数」。直方图是客观评价曝光质量的有效工具。自动曝光算法从简单的爬山法发展到场景自适应 AE,核心是让机器理解「当前在拍什么」。

我曾经在一个项目中踩过坑:用固定目标亮度 120 去拍雪景,结果雪地变成灰色。后来加入场景分类,雪景目标亮度调到 180,才还原出「雪白」的效果。嗯,这就是场景自适应的价值。