LV值计算的注意事项

3.5 关键追问:修改 AE 目标亮度后,LV 还能表示环境实际亮度吗?

如果保持外部环境亮度不变,只是修改目标亮度值。根据

LV= EV-log(iso_speed/100)

EV =AV+TV

由于TV、SV改变了,导致LV都有改变。

因此修改 AE 目标亮度后,LV 不能表示实际的环境的亮度。LV 会随目标亮度整体平移,平移量 = log2(新目标/旧目标)。
LV 表示的是"场景亮度相对标定目标的比值",而不是绝对环境亮度。

3.5.1 原因:AE 收敛方程的常数 C0 里藏着目标亮度

回顾 3.1 节第二步的收敛条件:

复制代码
H × G = Y_target / c = C0
              ↑
        AE 目标灰度!

C0 不是系统固有常数,它正比于 AE 目标亮度 Y_target。第 3.1 节第五步的最终结果:

复制代码
LV = log2(L) + [log2(k) - log2(C0) - log2(iso_base) + log2(100)]
                          ↑
                    含 log2(Y_target)

展开写就是:

复制代码
LV = log2(L) - log2(Y_target) + 常数

LV 中残留了一项 -log2(Y_target) 。之前说"LV 只含场景亮度",前提是

Y_target 固定不变------此时 -log2(Y_target) 并入常数,LV ∝ log2(L) 成立。

一旦修改目标亮度,这个"常数"就变了,LV 整体平移。

3.5.2 直观理解:LV 度量的是"曝光相对目标的偏差"

LV 的本质是 AE 闭环的不动点,而不动点的位置由参考点决定:

  • AE 的任务是把画面打到目标灰度
  • LV 记录的是"为了打到这个目标,相机用了多少曝光"
  • 目标调亮 → AE 给更多曝光 → EV 变小 → LV 变小(同一场景"看起来变暗"了)

所以 LV 实际度量的是:

复制代码
LV = log2( L / L_ref ) + 常数

其中 L_ref 是"AE 目标灰度对应的等效场景亮度"(由标定时的目标决定)。

改目标 = 改 L_ref = 平移整个 LV 刻度。

3.5.3 数值例子:目标从 50 调到 100(调亮一档)

场景不变:明亮商铺,真实 LV(原标定口径)= 8.91,iso_base = 50,增益固定 2x(iso_speed = 100)。

原目标 Y = 50 :AE 收敛于 F2.0, 1/120s,EV = 8.91,LV = 8.91 - 0 = 8.91

目标调到 Y = 100(×2,调亮一档) :画面要亮一档,AE 把曝光加大一档 :

F2.0, 1/60s

复制代码
EV = log2(4) + log2(60) = 2 + 5.91 = 7.91   (比原来小 1)
LV = 7.91 - log2(100/100) = 7.91            (比原来小 1)

环境亮度纹丝未动,LV 却从 8.91 掉到 7.91 ------按 Lux 换算 2.5×2^LV,

上报照度从 1200 lux 变成 600 lux,凭空"变暗"一档。

目标调暗到 Y = 25(×1/2):AE 把曝光减小一档,F2.0, 1/240s:

复制代码
EV = 2 + log2(240) = 9.91   (大 1)
LV = 9.91                    (大 1)  ← 凭空"变亮"一档
3.5.4 定量关系与修正方法

目标从 Y_cal(标定值)改为 Y_new,LV 的平移量为:

复制代码
ΔLV = -log2(Y_new / Y_cal)

验证: Y_new = 2×Y_cal → ΔLV = -1 ✓ (上例 8.91 → 7.91)
      Y_new = Y_cal/2 → ΔLV = +1 ✓

若确实需要运行时修改目标亮度,又想保持 LV 的物理意义,有两种做法:

复制代码
方法1 (推荐): 修正上报值
  LV_true = LV_report + log2(Y_new / Y_cal)
  即把目标变化量从 LV 中扣回去, 恢复到标定时的口径

方法2: 重新标定 Lux 系数
  保持 LV_report 原样, 重测 5.5 节的 A:
  A_new = A_old × (Y_cal / Y_new)
  Lux = A_new × 2^LV_report
  (本质相同: 平移量被打包进换算系数)
3.5.5 与 3.3 节反例的对比:两种"LV 失真"的本质
3.3 节反例(AE 未收敛) 本节(改 AE 目标)
操作 锁定曝光,拉增益 环境不变,改目标亮度
EV 是否变 不变 变(AE 重新收敛到新曝光)
LV 偏移量 +log2(增益倍数) -log2(目标倍数)
物理含义 当前曝光相对场景的偏差 场景相对新目标的偏差
是否"错误" 不是------正确反映过/欠曝量 不是"错误",但不再是绝对环境亮度

两者的共同本质:LV 永远忠实度量"当前曝光策略相对参考点的位置" 。

参考点(增益显式进入公式、目标隐含在收敛点里)任何一侧变动,LV 都会平移。

只有"AE 收敛 + 目标固定 + iso_base 标定准确"三个条件同时满足,

LV 才是纯环境亮度。

工程要点 :AE 目标亮度(含分区域权重、人脸逆光提升等动态目标调整)

是 LV/Lux 上报链路中最容易被忽视的平移源------增益和曝光参数的变化都被公式

显式抵消了,唯独目标亮度的变化直接烙在收敛点上。若产品有"逆光人脸提亮"

等动态目标功能,Lux 上报必须按 3.5.4 方法 1 同步补偿,否则夜间/逆光场景

Lux 会出现与目标调整幅度完全相关的系统性跳变。

3.5.6 方法 1 深入详解:为什么 LV_true = LV_report + log2(Y_new/Y_cal) 成立
(a) 修正公式的推导------把"被偷走的常数"加回来

从 3.5.1 节的结论出发。设标定时目标为 Y_cal,当前运行目标为 Y_new,

AE 收敛后 LV_report 的完整表达式是:

复制代码
LV_report = log2(L) - log2(Y_new) + C_fix

其中 C_fix 是与目标无关的固定常数(含 k、iso_base、log2(100) 等)。

我们想要的是"标定口径"的 LV,即假设目标仍是 Y_cal 时会算出的值:

复制代码
LV_true  = log2(L) - log2(Y_cal) + C_fix

两式相减:

复制代码
LV_true - LV_report = [log2(L) - log2(Y_cal) + C_fix] - [log2(L) - log2(Y_new) + C_fix]
                    = log2(Y_new) - log2(Y_cal)
                    = log2(Y_new / Y_cal)

移项即得修正公式:

复制代码
LV_true = LV_report + log2(Y_new / Y_cal)

直观解读 :目标从 Y_cal 改成 Y_new 时,LV 被平移了 -log2(Y_new/Y_cal)

(3.5.4 节的 ΔLV)。修正就是把这个平移量原样加回去 ------

目标调大多少倍,就补回多少个 log2;目标调小则补回负值。

场景项 log2(L) 和固定常数在相减时完全消掉,所以修正不依赖场景、
不依赖增益、不依赖曝光参数
,是一个纯加性补偿。

(b) 为什么"加回去"在数学上是严格的------修正后的 LV 恢复不动点性质

验证修正后的量是否重新成为"AE 不动点"(环境不变则修正后 LV 不变):

环境亮度 L 固定,目标从 Y_cal 改为 Y_new。AE 重新收敛,新收敛方程:

复制代码
H × G = Y_new / c   →   AE 给出的曝光量变为原来的 Y_new/Y_cal 倍
→ EV_new = EV_cal - log2(Y_new/Y_cal)

代入 LV_report 公式(iso_speed 项不变,因为增益路径没变):

复制代码
LV_report = EV_new - log2(iso_speed/100)
          = EV_cal - log2(Y_new/Y_cal) - log2(iso_speed/100)
          = LV_cal_口径 - log2(Y_new/Y_cal)

修正:

复制代码
LV_true = LV_report + log2(Y_new/Y_cal) = LV_cal_口径 ✓

逐项对消与 3.1 节 log2(G) 的抵消完全同构:

  • 目标变化在收敛点里"隐含"地平移了 EV(AE 行为)
  • 修正项"显式"地把同一个平移量加回去
  • 一隐一显,符号相反,目标的影响被彻底抹掉

修正后,无论目标怎么改,LV_true 都只随真实环境亮度 L 变化------

LV_true 恢复了"环境不变则读数不变"的不动点性质 ,

Lux = 2.5 × 2^LV_true 重新成立。

© 完整数值例子 1:静态改目标(延续 3.5.3 的场景)

场景:明亮商铺,真实照度 1200 lux(真实 LV = 8.91),iso_base = 50,

增益固定 2x(iso_speed = 100),标定目标 Y_cal = 50。

目标改为 Y_new = 100 后 AE 重新收敛:

复制代码
AE 把曝光加大一档: F2.0, 1/60s
EV   = log2(4) + log2(60) = 7.91
LV_report = 7.91 - log2(100/100) = 7.91        ← 比真实值低 1

应用修正:

复制代码
修正项 = log2(Y_new / Y_cal) = log2(100/50) = log2(2) = +1
LV_true = 7.91 + 1 = 8.91 ✓                    ← 精确回到真实值
Lux = 2.5 × 2^8.91 = 1200 lux ✓                ← 与照度计一致

反向验证(目标调暗):Y_new = 25,AE 收敛于 F2.0, 1/240s:

复制代码
EV = 2 + log2(240) = 9.91
LV_report = 9.91                                ← 比真实值高 1
修正项 = log2(25/50) = -1
LV_true = 9.91 + (-1) = 8.91 ✓

换目标前后对照表:

目标 Y_new AE 收敛设置 EV LV_report 修正项 log2(Y/50) LV_true
25 F2.0, 1/240s 9.91 9.91 -1 8.91
50(标定值) F2.0, 1/120s 8.91 8.91 0 8.91
100 F2.0, 1/60s 7.91 7.91 +1 8.91
200 F2.0, 1/30s 6.91 6.91 +2 8.91

目标每翻一倍,LV_report 掉 1、修正项涨 1,两者相加恒为 8.91------

修正后的读数对目标变化完全免疫。

(d) 完整数值例子 2:动态目标(逆光人脸提亮场景)

真实产品中目标亮度往往逐帧变化。设某安防相机:

  • 标定目标 Y_cal = 56(Q8 定点习惯值,对应 8bit 的 22%)
  • 普通场景目标 56;检测到逆光人脸时目标提升到 112(提亮一档)

时间线(环境为傍晚室内,真实 LV = 6.3,约 100 lux,iso_base = 50):

帧 场景 Y_new AE 收敛 LV_report 修正项 LV_true 未修正 Lux 修正后 Lux
t0 无人脸 56 EV=6.3 6.3 0 6.3 98 lux 98 lux
t1 人脸入画 112 EV=5.3 5.3 +1 6.3 49 lux 98 lux
t2 人脸出画 56 EV=6.3 6.3 0 6.3 98 lux 98 lux

未修正的后果 :人脸入画瞬间 Lux 上报从 98 跳到 49(凭空"变暗"一档),

出画又跳回------环境明明没变,Lux 曲线出现与目标调整完全同步 的方波跳变。

若上层用 Lux 做日夜切换/补光灯控制,会在人脸出入画时反复误触发。

修正后 :LV_true 恒为 6.3,Lux 恒为 98 lux,曲线平滑。

注意画面本身确实变亮了(这是提亮的目的),但亮度状态量与画面观感解耦 ------

这正是"状态量"与"控制量"分离的意义:AE 用目标控制画面,

Lux 上报用修正后的 LV 描述环境。

(e) Q8 定点实现

修正项也是纯 log2,可直接复用工程的定点 log2(fixed_log2_apex),

或更简单------目标值通常是有限集合(P-line 档位/场景模式),可预计算查表:

c 复制代码
/* Y_cal: 标定时的 AE 目标 (如 56)
 * Y_new: 当前帧 AE 实际使用的目标
 * 返回 Q8 修正项, LV_true_q8 = LV_report_q8 + corr_q8          */
int32_t lv_target_corr_q8(uint32_t y_new, uint32_t y_cal)
{
    /* corr_q8 = 256 * log2(y_new / y_cal)
     * 用定点 log2: log2_q8(x) 以 Q8.8 输入 256=x 输出            */
    if (y_new == 0 || y_cal == 0) return 0;
    return fixed_log2_q8((int64_t)y_new * 256 / y_cal);  /* Q8 */
}

/* Lux 上报链路 */
LV_true_q8 = LV_report_q8 + lv_target_corr_q8(y_target_cur, Y_CAL);

三个实现要点:

  1. 修正项必须用"AE 本帧实际收敛所用的目标" 。若目标在 AE 收敛过程中

    逐帧变化,收敛瞬间的 LV_report 对应的是"最后一步用的目标",

    用错目标值会留下残余误差(目标差 1 档 → 残余 1 EV)。

    工程上取"AE 稳定判据(连续 N 帧曝光不变)成立那一帧的目标"最稳妥。

  2. 修正加在 Lux 上报路径,不加在 AE 反馈路径 。AE 内部用 LV_report

    与目标比较来调曝光(err = LV_target - LV_current),这条路径里

    目标变化本来就是"信号"而不是"误差",加了修正反而破坏控制。

  3. 标定 A(5.5 节)时必须把修正项置零或固定目标 ,否则目标平移量

    会被吸收进 A,之后动态目标再变化就会双重补偿。

(f) 方法 1 与方法 2 的等价性证明

方法 2 把平移量打包进 Lux 系数:A_new = A_old × (Y_cal/Y_new),则:

复制代码
Lux_方法2 = A_new × 2^LV_report
          = A_old × (Y_cal/Y_new) × 2^LV_report
取 log2:  log2(Lux_方法2) = log2(A_old) + LV_report + log2(Y_cal/Y_new)
                          = log2(A_old) + LV_true        (由 (a) 的修正公式)
          → Lux_方法2 = A_old × 2^LV_true = Lux_方法1 ✓

两者数学上完全等价,区别只在工程形态:

方法 1(修正 LV) 方法 2(重标 A)
修正位置 LV 计算处(源头) Lux 换算处(末端)
目标动态变化 每帧实时修正,天然支持 A 是静态常数,无法跟随动态目标
下游 LV 使用方 拿到的直接是物理口径 拿到的是"偏移口径",需自行知晓
适用场景 目标会运行时变化(动态目标/用户 EV 补偿联动) 目标固化的产品,改动最小

结论 :只要目标亮度会动态变化,方法 1 是唯一正确选择;

方法 2 只适用于目标永久固定的场合。

3.5.7 工程落地:ISP 调试改了目标亮度,如何保证 LV 永远等于环境实际亮度?

问题背景 :iso_base/Lux 系数标定完成后,ISP 图像效果调试是持续进行的------

调优人员经常改 AE 目标亮度(调画面明暗观感),且不会通知 做 Lux/ISO

标定的人。标定时的 Y_cal 与量产固件里的实际目标 Y_tuning 天然存在差异。

如何让 LV 在任何调参之后都自动保持"环境实际亮度"的物理意义?

核心答案:不要依赖"目标不变"这个脆弱假设,而是把目标修正
固化进 LV 计算链本身------LV 计算时永远显式除掉当前生效的目标值。

(a) 根本性方案:把 Y_target 写进 LV 公式,而不是藏在常数里

回顾 3.5.1 节,LV 的完整表达式是:

复制代码
LV = log2(L) - log2(Y_target) + C_fix

标定时 Y_target = Y_cal 固定,-log2(Y_cal) 被并入常数,公式简化为

LV = log2(L) + 常数------这个简化正是脆弱性的来源 :它隐含假设

"目标永远等于标定值"。

根治方法是不做这个简化,让 LV 计算公式显式包含当前目标:

复制代码
LV_true = AV + TV - SV + log2(Y_cur / Y_cal)
                        ↑当前帧AE实际用的目标  ↑标定时的目标(固化常量)

这样无论调优人员把目标改成多少,修正项自动跟随,LV_true 恒为

标定口径的环境亮度。调参自由度与状态量物理意义彻底解耦:

  • 调优改目标 → 只影响画面观感和 AE 行为(本来就该如此)
  • LV/Lux 上报 → 自动补偿,永远描述真实环境
(b) 配套的工程纪律(三条,缺一不可)

纪律 1:Y_cal 成为受控常量,与标定数据绑定

复制代码
- Y_cal (如 56) 与 iso_base、Lux 系数 A 一起存入标定数据区/OTP,
  与算法参数分离, 调优人员不可修改
- 标定数据区只随 sensor/模组标定流程更新, 不随 ISP 调参版本更新

纪律 2:LV 计算处必须能拿到"当前帧 AE 实际使用的目标"

复制代码
- AE 模块每帧输出 y_target_cur (本帧收敛用的目标, 含动态目标调整)
- LV 计算函数签名显式带上该参数, 不允许在 LV 内部另读一份
  "配置表目标"------两处读数不一致是常见 bug 源
- 动态目标(人脸提亮等)天然被覆盖: 用哪个目标收敛, 就用哪个修正

纪律 3:验收用照度计闭环,不信任任何中间推导

复制代码
- 每次大版本调参合并后, 用照度计 + 灰板复测 2~3 个照度点:
  |Lux_report - Lux_照度计| < 0.1 EV 即通过
- 该测试不依赖任何代码审查------无论谁改了什么, 只要 LV 链路
  被破坏, 此测试立刻暴露
© 数值例子:调优改目标后,修正机制自动生效

延续 3.5.6© 场景:1200 lux 商铺,Y_cal = 50(固化在标定区),

iso_base = 50,增益 2x。

调优人员把目标从 50 改成 80(+0.68 档),未告知标定方:

复制代码
AE 重新收敛: 曝光加大 log2(80/50)=0.68 档 → F2.0, 1/75s
EV = 2 + log2(75) = 8.23
LV_report(无修正) = 8.23 - 0 = 8.23          ← 偏离真实值 0.68 EV

LV 计算链自动修正:

复制代码
修正项 = log2(Y_cur / Y_cal) = log2(80/50) = 0.68
LV_true = 8.23 + 0.68 = 8.91 ✓               ← 自动回到真实值
Lux = 2.5 × 2^8.91 = 1200 lux ✓

调优改任何目标值(56、80、112......),LV_true 恒为 8.91------

修正项与目标变化逐档对消,机制对调参行为完全透明。

(d) 若无法改造 LV 计算链(遗留代码)的降级方案

若 LV 计算函数无法加参数,退而求其次:

复制代码
降级方案: 在 Lux 上报出口处统一补偿
  lux_q8 = A_q8 × 2^((LV_report_q8 + corr_q8) >> 8)
  corr_q8 = log2_q8(y_target_cur × 256 / Y_CAL)

风险与对策:
  - 遗留代码里 LV 的其他使用方(场景分类/日夜切换)拿到的仍是
    偏移口径 → 必须梳理全部 LV 消费点, 逐一确认口径
  - 更稳妥: 在 LV 计算函数出口处直接加 corr (单点修改),
    保证所有下游拿到统一物理口径
(e) 总结:三层防线
层级 措施 防什么
第 1 层(根治) LV 公式显式含 log2(Y_cur/Y_cal),修正项自动跟随 任何目标修改,含动态目标
第 2 层(纪律) Y_cal 入标定受控区;AE 每帧输出实际目标给 LV 链 口径分裂、读数不一致
第 3 层(验收) 照度计闭环回归测试,阈值 0.1 EV 一切未被意识到的链路破坏

一句话 :LV 的物理意义不靠"没人改参数"来保证,而靠

"参数改了,公式自动知道"来保证------把目标亮度从隐含常数

升级为显式输入,是唯一健壮的做法。

3.6 工程实践讨论:手机 AE 是否都用固定目标亮度?

原命题 :"手机 AE 中不同 sensor 基本都用相同的固定目标亮度(标定和实际使用一致);

要不同亮度效果就调其他参数,不动目标亮度;动了目标亮度,算出的 LV 就不准了。"

结论:方向正确,是主流工程实践,但需要三处精确化。

3.6.1 命题中准确的部分

(1) "LV 相对固定目标而言"------准确,这是 LV 的数学性质

由 3.5.1 节,LV = log2(L) − log2(Y_target) + C_fix。LV 是 AE 闭环的不动点,

而不动点的位置由目标亮度唯一决定。不存在"绝对 LV",只存在"某目标口径下的 LV" 。

标定时用什么目标,运行时就必须还是那个目标,LV 的数值口径才不变。

(1a) 原理详解:为什么"不动点由目标唯一决定"、"不存在绝对 LV"

① 先把"AE 闭环"写成迭代映射,看清不动点在哪

AE 每帧做的事可以抽象成一个映射 f:输入当前的 LV 观测值,输出调整后的 LV。

设当前曝光状态对应的 LV 为 x,AE 统计画面平均亮度 Y_cur,与目标 Y_target 比较:

复制代码
误差 err = log2(Y_cur) - log2(Y_target)
新曝光:  x_next = x - err        (画面偏亮就减曝光, 偏暗就加曝光)

而 Y_cur 由物理链路决定:Y_cur = c · L · (T/N²) · G = c · L · G · 2^(-x+常数)。

代入整理(细节即 3.1 节第三步),迭代映射化简为:

复制代码
x_next = x - [log2(L) - log2(Y_target) + C_fix - x]  =  log2(L) - log2(Y_target) + C_fix

关键观察:x_next 与 x 无关! 无论从什么初始曝光出发,一步之后都到达

同一个值 x* = log2(L) − log2(Y_target) + C_fix,且 x* 代回去满足 x* = f(x*)------

这就是不动点。AE 收敛 = 到达不动点;收敛后读出的 LV 恰好等于 x*。

② 不动点的位置由谁决定------三个自变量中只有 L 是"环境"

复制代码
x* = log2(L) − log2(Y_target) + C_fix
       ↑环境      ↑AE目标        ↑标定常数(iso_base等)
  • L 变 → 不动点移动 → LV 跟随环境(这是 LV 有用的原因)
  • Y_target 变 → 不动点同样移动 → LV 跟随目标(这是 LV 口径依赖目标的原因)
  • 在不动点公式里,L 和 Y_target 的地位完全对称 ------都是"亮度",都进 log2,
    一个来自场景,一个来自算法配置。LV 无法区分"环境变暗了"和"目标调亮了",
    因为这两种情况对收敛点的影响逐比特相同。

这就是"不存在绝对 LV"的数学含义:x 是二元函数 x (L, Y_target),

不是一元函数 x*(L)。只有把 Y_target 冻结成常数,它才退化为 x*(L),
"LV ↔ 环境亮度"的一一映射才成立。冻结与否不是数学强制的,
是
工程约定**------约定一旦破坏(改目标),映射立刻退回二元。

③ 类比:LV 是一把"零点由目标校准的尺子"

LV 度量的是比值 L/Y_target 的 log2,本质是相对量:

复制代码
LV = log2( L / Y_target ) + C_fix
     ↑"场景是目标的多少倍"

就像摄氏温标的 0 度是"水的冰点"这个人为参考点 ------换一个参考点

(华氏、开尔文)温度数值全变,但"哪杯水更热"的判断不变。

LV 的参考点就是 Y_target:目标 56 时 LV=8.91 的场景,和目标 112 时

LV=7.91 的场景,物理亮度完全相同 (都对应 1200 lux),

只是尺子的零点挪了一格。尺子本身没有"绝对零度"式的天然锚点------

锚点是标定时人为选的。

④ 数值例子:三个不动点,同一个场景

同一 1200 lux 场景(log2(L)+C_fix = 8.91 + log2(56) 口径),三台设备目标不同:

设备 Y_target AE 收敛设置 不动点 x* = LV_report 未补偿 Lux
甲(标定口径) 56 F2.0, 1/120s 8.91 1200 ✓
乙(目标调亮一档) 112 F2.0, 1/60s 7.91 600 ✗
丙(目标调暗半档) 40 F2.0, 1/170s 9.26 1540 ✗

三台设备拍的照片亮度各不相同(乙最亮、丙最暗),各自的 LV 都"正确"地
描述了自己口径下的场景
------乙的 7.91 精确等于"场景亮度相对 112 目标的比值",

没有任何计算错误。但三台设备的 LV 互相不可比 :甲乙丙对同一环境的

读数差恰好是 log2(Y_target 比值)(乙比甲低 1 = log2(112/56),

丙比甲高 0.35 = log2(56/40))。

⑤ 不动点性质的验证实验(可实机复现)

实验 1(验证"是不动点"):对甲设备人为锁定错误曝光(过曝 2 档)后放开:

复制代码
t0: 锁定曝光, LV_report = 10.91 (偏离不动点 +2, 画面过曝)
t1: 放开, AE 迭代: x1 = 10.91 - err, err = +2 → x1 = 8.91
t2: 已在不动点, err = 0, x2 = 8.91 → 稳定
→ 无论从哪个初始曝光放开, 都回到 8.91: 不动点唯一 ✓

实验 2(验证"不动点随目标移动"):对甲设备把目标 56 → 112:

复制代码
t0: 旧不动点 8.91, 画面 1200 lux 口径正常
t1: 改目标, AE 观测到 Y_cur=56 < Y_target=112, err = -1
    → 加曝光一档 → x1 = 8.91 - (-1) = 7.91
t2: Y_cur = 112 = Y_target, err = 0 → 稳定在新不动点 7.91
→ 环境没变, 不动点从 8.91 挪到 7.91, 挪动量恰为 log2(112/56) ✓

两个实验合起来的结论:AE 保证收敛到不动点(对初始条件鲁棒),
但不保证不动点对应"标定口径"------不动点在哪,完全听目标的
。

所以"LV = 环境亮度"这条性质的所有权链是:

复制代码
AE 收敛 (保证到达不动点) + 目标恒等于标定值 (保证不动点位置不变)
→ LV 才等于标定口径的环境亮度

第一环由算法自动保证,第二环没有任何机制自动保证 ------它靠的是

"没人去改目标"这个管理约定。3.5.7 节的三层防线,本质就是把第二环

从"管理约定"升级为"机制保证"。

(2) "不同 sensor 基本用相同目标"------基本属实,是行业惯例

主流手机/安防平台的 AE base target 高度集中在 8bit 50~56(约 20%~22% 灰):

平台/惯例 典型 base target (8bit)
Qualcomm Chromatix 默认 52~55
MTK 常用配置 50~55
安防 sensor 常用 50~56(Q8 习惯取 56 ≈ 22%)

统一到 20% 左右的物理原因:

  • 接近 18% 中性灰:测光体系的物理锚点,AE 收敛点与灰卡标定体系自洽
  • 留 headroom:平均 20% 时高光还有约 2.3 档余量(20%→100% 是 log2(5)≈2.3 EV),防高光溢出
  • SNR 最优:再低浪费动态范围,再高则高光 clip 风险陡增

统一目标的工程收益:iso_base 标定流程、Lux 系数 A、P-line 表、场景分类阈值

(LV<3 夜景 / 3~8 室内 / >11 晴天)全部可跨项目、跨 sensor 复用 。

若每个项目目标各异,这些标定数据和阈值全部要重标重调。

(3) "调效果不动目标"------准确,且是推荐做法(举例见 3.6.3)

(4) "动了目标 LV 不再准确"------准确(机理见 3.5 节,此处不重复)

3.6.2 命题需要精确化的三个地方

(1) "所有 LV 都相对固定目标"------目标并非永远不动,而是分了"层"

实际产品中目标亮度分三层,性质完全不同:

层 例子 是否变化 与 LV 口径的关系
层1: base target 56(8bit 22%) 标定后固化,几乎不动 LV/Lux 上报的口径锚点
层2: 分照度目标表 高照度压到 52 防过曝、低照度提到 64 降噪 随 BV/照度连续变化 控制量,Lux 上报需补偿或排除
层3: 场景动态目标 逆光人脸提亮到 112、夜景模式提亮 逐帧/逐场景变化 控制量,同上

所以准确的说法是:LV 的"上报口径"只绑定层1 的 base target;
层2/层3 的目标变化属于 AE 控制行为,必须按 3.5.4 方法 1 补偿
(或设计上就让 Lux 链路只使用 base target 口径的收敛结果)
。

"目标固定"不是"从来没人动过目标",而是"动目标的影响被链路设计吸收了"。

(1a) 原理详解:为什么上报口径只绑定 base target,层2/层3 怎么处理

① 为什么口径锚点只能是 base target------由 LV 公式的结构决定

LV 的收敛点表达式(3.5.1 节):

复制代码
LV_report = log2(L) − log2(Y_eff) + C_fix

其中 Y_eff 是"AE 最后一次收敛实际使用的目标" ------注意不是配置表里

的某个静态值,而是层1/层2/层3 叠加后本帧生效的那个值:

复制代码
Y_eff = base_target × f_照度表(BV) × f_场景(人脸/夜景/逆光...)
         ↑层1(固定)      ↑层2(随照度)      ↑层3(随场景)

要 LV_report = log2(L) + 常数(纯环境量),必须 log2(Y_eff) 是常数,

即 Y_eff 恒等于标定时的 Y_cal 。三层中只有层1 满足"恒定"------

所以口径锚点只能 是 base target,这不是选择,是排除法的结果:

层2 随 BV 连续变、层3 随场景跳变,谁都不可能充当常数。

② 关键有利条件:层2/层3 的平移量是"已知的",不是"未知的"

层2/层3 造成 LV 平移 −log2(Y_eff/Y_cal),这与噪声、与 iso_base 偏差

有本质区别:Y_eff 是算法自己设置的,每一帧都精确知道 。

未知误差只能标定或容忍,已知平移可以精确扣除------这就是"必须按

3.5.4 方法 1 补偿"的可行性依据:

复制代码
LV_true = LV_report + log2(Y_eff / Y_cal)     (3.5.4 方法1, Y_eff 逐帧已知)

补偿后 LV_true 恢复不动点性质(3.5.6(b) 已证明),Lux 链路对

层2/层3 完全免疫。

③ 两条落地路线的完整对比

路线 A:逐帧补偿(3.5.4 方法 1)

AE 每帧输出 y_eff_cur(本帧实际生效目标),LV 计算处加修正项。

路线 B:设计上隔离------让 Lux 链路只消费 base target 口径的收敛结果

利用一个重要事实:LV = AV + TV − SV 的计算公式本身不含目标 ,

目标只通过"收敛点"隐式进入。所以只要保证"计算 LV 用的 (N,T,gain)

是 AE 在 base target 口径下收敛出来的",LV 就自动是标定口径,

一行补偿代码都不用写。具体有三种实现形态:

复制代码
B1 (门控): 层2/层3 生效期间冻结 Lux 上报, 退出后恢复更新
B2 (旁路): 层2/层3 生效期间, Lux 改由"曝光直算路径"提供
           Lux ≈ C_exp / (T × G_total)   (由 iso_base 标定 C_exp)
           ------ 该路径同样只在 base 口径收敛时正确, 故需配合门控
B3 (双收敛): AE 内部并行维护一个"虚拟 base 口径收敛器":
           用当前 LV 估计值查 base target 的 P-line, 得到
           "假如目标没被层2/层3 修改, AE 本应使用的 (N,T,gain)"
           → 用这套虚拟参数算 LV/Lux, 与实际曝光解耦

④ 数值例子:夜景模式提亮,两条路线的效果

场景:夜晚街道,真实 40 lux(真实 LV = 4.0),base target = 56,

iso_base = 50。夜景模式把目标提到 112(提亮一档,层3 生效)。

复制代码
AE 重新收敛: 曝光加大一档 (如 1/30s → 1/15s)
LV_report = 4.0 − log2(112/56) = 3.0
未补偿 Lux = 2.5 × 2^3.0 = 20 lux   ← 凭空"变暗"一半 ✗

路线 A(逐帧补偿):

复制代码
修正项 = log2(112/56) = +1
LV_true = 3.0 + 1 = 4.0 → Lux = 40 ✓
夜景模式全程 Lux 连续正确上报; 用户从街道走进 5 lux 巷子,
Lux 平滑降到 5 --- 状态量始终鲜活

路线 B1(门控冻结):

复制代码
夜景模式生效期间: Lux 保持进入前的 40 lux 不更新
退出夜景模式: AE 回到 base 口径收敛, LV_report = 4.0, Lux 恢复更新
若用户在夜景模式期间环境从 40 lux 变到 5 lux:
  → Lux 仍报 40, 直到退出模式才跳到 5 (滞后 + 跳变)

路线 B3(虚拟收敛):

复制代码
实际曝光: 1/15s (夜景口径) → LV_report = 3.0 (只给 AE 反馈用)
虚拟收敛: LV 估计 4.0 查 base P-line → 虚拟 (N,T,gain) = 1/30s
          → LV_virtual = 4.0 → Lux = 40 ✓
AE 控制与 Lux 上报彻底解耦, 但要多维护一套查表逻辑

⑤ 两条路线的选择依据

路线 A(补偿) 路线 B1(门控) 路线 B3(虚拟收敛)
实现代价 一行加法 + AE 输出 y_eff 状态标志 + 冻结逻辑 双份 P-line 查表
层2/层3 期间 Lux 连续正确 冻结(滞后) 连续正确
环境突变响应 实时 退出模式才响应 实时
风险点 y_eff 取值必须与收敛帧一致(3.5.6(e) 要点1) 冻结期 Lux 失真 虚拟收敛与实际收敛可能发散
适用 有动态目标功能的产品(主流选择) 目标调整短暂/低频 AE 与 Lux 架构彻底分离的平台

工程结论 :层2/层3 的目标变化对 AE 控制是"信号"(就是要画面变亮),

对 Lux 上报是"误差"(环境没变读数不能变)------同一个量在两条消费链里
身份相反,所以必须在链路上分开处理
:AE 反馈用未补偿的 LV_report,

Lux/场景分类用补偿后的 LV_true(路线 A)或 base 口径的收敛结果(路线 B)。

这正是"上报口径只绑定 base target"的完整含义:不是层2/层3 不许存在,

而是它们的痕迹不允许出现在上报链路里。

(1b) 原理详解:为什么同一个量在两条消费链里"身份相反"

① 先明确两条消费链各自要回答的问题

LV 这个量在系统里被两条完全独立的链路消费,它们要回答的问题不同:

复制代码
链路1 (AE 反馈环):  "画面离我想要的样子还差多少?"
                    → 比较对象是 Y_target (当前生效目标)
                    → LV_report 恰好编码了这个偏差, 是"信号"

链路2 (状态上报):   "环境现在有多亮?"
                    → 比较对象是物理世界 (lux)
                    → LV_report 里混入的目标痕迹是"误差"

② 为什么对 AE 反馈环,目标变化是"信号"------它就是控制量本身

AE 反馈环的误差定义(3.6.1(1a) ①):

复制代码
err = log2(Y_cur) − log2(Y_target)

夜景模式把目标 56→112 后,err 立刻变成 −1,AE 据此加一档曝光------

这个 err 正是设计者想要的 :目标改动的全部目的就是制造这个 err,

驱动曝光移动。此时如果把 LV 补偿成 LV_true 再喂给 AE 反馈环会怎样?

复制代码
错误做法: AE 反馈用 LV_true
  err' = LV_target − LV_true
  夜景模式: 目标 112 (LV_target 口径随之平移 −1), LV_true 不含平移
  → err' = (LV_target_新口径) − LV_true
  → 平移量在等式两侧各出现一次, 相互抵消
  → err' = 0, AE 认为已经收敛, 不加曝光!
  → 夜景模式失效: 目标改了, 画面纹丝不动

补偿项在反馈环里被"自消" ------因为 LV_target(查表用的目标口径 LV)

和 LV_true 若用同一口径,目标平移在减法两侧同号出现,控制误差归零。

这就是"AE 反馈用未补偿的 LV_report"的数学原因:反馈环内部
口径自洽即可,目标平移必须保留在环内才能驱动曝光移动
。

③ 为什么对 Lux 上报链,目标变化是"误差"------它破坏了状态量的定义

状态量的定义(第 3 节):环境不变则读数不变。Lux 链路的全部价值

建立在这个性质上------下游(日夜切换、补光灯、曝光指数显示、

多帧合成触发)都假设"Lux 变化 = 环境变化"。

目标变化破坏这个假设的方式(3.6.2(1a) ④ 已算过):夜景提亮一档,

Lux 从 40 凭空掉到 20。下游看到的是"环境突然变暗一半"------

这是一个假事件 。假事件的危害不是"数值不准"这么简单,而是

它与环境真事件在下游眼里无法区分:

复制代码
下游视角:
  事件A (真): 用户走进树荫, 40 lux → 20 lux   → 应该触发夜切预备
  事件B (假): 夜景模式提亮一档, 40 lux → 20 lux → 不应该触发任何东西
  两条 Lux 曲线逐比特相同 → 下游必然误触发

④ "身份相反"的严格表述:同一个平移量,在两个环里的符号角色不同

设目标平移量 δ = log2(Y_eff/Y_cal)。考察它在两条链路里的出现位置:

复制代码
AE 反馈环:  err = [LV_target(含δ口径)] − [LV_report(含δ)]
            δ 在两侧同号 → 相减后保留 → 驱动曝光 → δ 是"信号"

Lux 链路:   Lux = A × 2^LV_report, LV_report 含 −δ 的平移
            δ 单侧出现 → 直接污染读数 → δ 是"误差"
            修正: LV_true = LV_report + δ → δ 被显式扣除

关键区别:反馈环是"差分结构"(两个同口径量相减),平移量在
两侧成对出现、相互加强控制;上报链是"直通结构"(单量直接换算),
平移量单侧出现、直接落进读数
。同一个 δ,差分结构里是驱动力,

直通结构里是污染源------这就是"身份相反"的数学本质。

⑤ 反例:两条链路混用一口径的两种灾难

灾难 1:上报链用了未补偿的 LV_report(③ 的假事件)

延续 3.6.2(1a) ④ 的夜景例子,加上下游日夜切换阈值(Lux < 15 触发夜切):

复制代码
时间线 (环境恒定 40 lux, 夜切阈值 15 lux):
t0: 普通模式, Lux=40, 不触发 ✓
t1: 用户开夜景模式, 目标 56→112
t2: AE 收敛, Lux 掉到 20 ------ 仍高于 15, 未触发 (侥幸)
t3: 用户再开"极致夜景", 目标 56→224 (再提亮一档)
t4: AE 收敛, Lux 掉到 10 < 15 → 触发夜切!
    → 夜切把曝光进一步拉长, 与夜景模式的提亮目标打架
    → 画面闪烁/来回切换 (夜切退出条件也满足不了, 死循环边缘)

灾难 2:AE 反馈环用了补偿后的 LV_true(② 的自消)

复制代码
时间线 (环境 40 lux, 夜景模式目标 112):
t0: 普通模式收敛, LV_true = LV_report = 4.0
t1: 开夜景模式, 目标 112
t2: 若 AE 用 LV_true 反馈: err = LV_target − LV_true
    LV_target 也按 base 口径记录 (4.0), LV_true = 4.0 → err = 0
    → AE 不动, 画面亮度不变
    → 夜景模式"开启成功"但毫无效果, 用户投诉"夜景模式没用"

两个灾难方向相反(一个误动作、一个不动作),根源相同:

给链路喂了错误身份的 LV。

⑥ 正确架构:单点计算、双口径输出

工程上最清晰的实现是 LV 只算一次,出口处分叉成两个口径:

c 复制代码
/* LV 只计算一次 (单点, 保证口径一致性) */
lv_report_q8 = av_q8 + tv_q8 - sv_q8;            /* 未补偿, AE 反馈用 */
corr_q8 = log2_q8((int64_t)y_eff_cur * 256 / Y_CAL);  /* 本帧生效目标修正 */

/* 出口分叉: 两条消费链各取所需 */
lv_for_ae_q8   = lv_report_q8;                        /* 反馈环: 保留 δ */
lv_for_state_q8 = lv_report_q8 + corr_q8;             /* 上报链: 扣除 δ */

lux_q8      = lux_from_lv(lv_for_state_q8);           /* Lux 上报 */
scene_class = classify_scene(lv_for_state_q8);        /* 场景分类 */
night_switch = (lux_q8 < NIGHT_TH_Q8);                /* 日夜切换 */
/* AE 反馈环内部: err = lv_target_q8 - lv_for_ae_q8;  */

三条纪律:

复制代码
1. 单点计算: lv_report 只在一处算, 两条链都从它分叉
   → 杜绝"两处各算一遍、口径悄悄不一致"的 bug 源
2. 命名显式: lv_for_ae / lv_for_state 强制使用者声明用途
   → code review 时口径混用一眼可见
3. 修正项与目标同源: corr_q8 的 y_eff_cur 必须取自 AE 本帧
   收敛实际用的目标 (3.5.6(e) 要点1), 不能另读配置表

⑦ 数值例子:正确架构下的完整时间线

环境恒定 40 lux,用户操作:开夜景(目标 112)→ 走进 5 lux 巷子 → 关夜景:

帧 场景/操作 Y_eff AE 收敛 LV_report corr LV_true Lux 下游行为
t0 普通模式 56 1/30s 4.0 0 4.0 40 正常
t1 开夜景 112 1/15s 3.0 +1 4.0 40 Lux 不跳变 ✓
t2 走进巷子 112 1/120s 1.0 +1 2.0 5 Lux 平滑下降 ✓
t3 关夜景 56 1/240s 2.0 0 2.0 5 Lux 不跳变 ✓

对照两条错误架构:

复制代码
若上报链用 LV_report (灾难1):  t1 处 Lux 40→20 假跳变, t3 处 5→10 假跳变
若 AE 反馈用 LV_true (灾难2):  t1 处 err=0, 曝光停在 1/30s, 夜景无效
正确架构: 画面按意图变亮/变暗 (AE 链), Lux 曲线只反映环境 (上报链)

t1→t2 期间画面从"夜景提亮"平滑过渡到"巷子更暗",两个变化在画面上

叠加,但 Lux 曲线只走出"40→5"一段------环境真相 。画面观感与

状态量读数各说各话、互不污染,这就是"链路分开处理"的最终形态。

⑧ 与 3.5.7 三层防线的关系

3.5.7 防的是"调优改目标没人知道"(配置漂移),本节防的是

"动态目标本身是功能"(设计使然)。两者共用同一套修正机制

(LV_true = LV_report + log2(Y_eff/Y_cal)),区别只在 Y_eff 的来源:

复制代码
3.5.7 场景: Y_eff = 调优改过的静态目标 (长期恒定, 但值可能≠Y_cal)
本节场景:   Y_eff = 层2/层3 动态目标 (逐帧/逐场景变化)
统一公式:   LV_true = LV_report + log2(Y_eff / Y_cal)   (Y_eff 永远取"本帧实际生效值")

所以 3.5.7 的"根本性方案"(LV 公式显式含 log2(Y_cur/Y_cal))

天然同时覆盖本节------一个机制,防两种漂移 。这也是为什么

修正项必须挂在"本帧实际生效目标"上而不是任何静态配置上:

静态配置读数只能覆盖 3.5.7,覆盖不了层2/层3。

(2) "调其他参数满足亮度效果"------有一个隐含的技术前提:AE 统计位置

"动 gamma/tone mapping 不动目标"能成立,前提是 AE 统计在 raw 域
(BLC 之后、gamma 之前)
。此时:

  • 调 gamma → 只改变 ISP 输出观感,raw 域统计不变 → AE 收敛点不动 → LV 稳定 ✓
  • 若 AE 统计在 gamma 之后的 Y 域 → 调 gamma 等效于调目标 → 收敛点移动 → LV 平移 ✗

这是很多平台坚持 raw 域统计(或统计前先做逆 gamma 归一)的深层原因之一:

把"观感调整"与"曝光状态量"在信号链上解耦 。评审 AE 设计时,

统计位置与目标口径必须一起确认,只看目标值是否固定是不够的。

(3) "用户 EV 补偿"是隐藏的例外------它等效于改目标

用户手动 EV +1 档,AE 收敛点移动 1 档,效果与把目标翻倍完全等价

(都是要求画面亮一档)。此时 LV_report 会掉 1 EV。行业惯例的处理是:

c 复制代码
/* Lux 上报使用不含 EV comp 的 LV */
LV_for_lux = AV + TV - SV + log2_q8(Y_base / Y_cal);   /* 不加 EV comp 项 */
/* 或等价地: LV_for_lux = LV_report + EV_comp_q8 */

即 EV comp 平移被显式排除在 Lux 口径之外 ------用户故意过曝是"意图",

不是"环境变亮了"。这与 3.5.4 方法 1 的补偿公式同构,只是符号方向相反。

3.6.3 数值例子对比:调 gamma vs 调目标

同一场景(1200 lux 商铺,真实 LV=8.91),两种"画面提亮一档"的手段:

手段 A:gamma 提亮(AE 统计在 raw 域)

复制代码
raw 域统计不变 → AE 收敛点不动: F2.0, 1/120s, gain 2x
EV = 8.91, LV_report = 8.91, Lux = 1200 ✓ 全部稳定
画面: 输出变亮一档 (观感目标达成)

手段 B:目标 56 → 112(AE 统计无论在哪都会响应)

复制代码
AE 重新收敛: F2.0, 1/60s (曝光加大一档)
EV = 7.91, LV_report = 7.91 (掉 1), 未补偿 Lux = 600 ✗ (凭空"变暗"一半)
画面: 输出变亮一档 (观感目标同样达成)
手段 A (gamma) 手段 B (改目标)
画面观感 亮一档 亮一档
LV_report 8.91(不变) 7.91(掉 1)
Lux 上报 1200(正确) 600(错误,需补偿)
场景分类阈值 不受影响 全部阈值需重校
跨机型一致性 保持 破坏(若各机型目标不同)
AE 收敛行为 不变 收敛点移动,收敛过程重走

两种手段观感等价,但对 LV/Lux 链路的影响天差地别 ------这就是

"调效果优先动 gamma/tone mapping,不动目标"的完整理由。

相关推荐
敢敢のwings1 小时前
SimpleMemVLA 深度解读:把原生视频上下文变成机器人的记忆
数码相机·机器人·音视频
敢敢のwings9 小时前
Super Odometry 2.0:相机与激光雷达退化后,机器人如何继续估计运动
人工智能·数码相机·机器人
高升说1 天前
手眼方案怎么选:眼在手上与眼在手外的工程对比
人工智能·数码相机
come112341 天前
手机与相机拍照入门
数码相机·智能手机
鹿野素材屋1 天前
U3D切换场景时候变黑怎么处理
数码相机·3d
GlobalInfo2 天前
2026年全球机器人用超平执行器市场研究报告:市场规模达7.51亿美元,人形机器人商业化与轻量化运动控制需求推动行业增长
大数据·人工智能·数码相机·microsoft·机器人
LaughingZhu2 天前
Product Hunt 热榜 2026-11-02:Screen Studio 4.0、ClawsGO Science、Riverside Agents
人工智能·深度学习·神经网络·数码相机·搜索引擎·百度
乐橙开放平台2 天前
离岗检测怎么实现?通过客流相机或 AI 摄像头识别岗位区域无人状态,再推送告警消息
人工智能·笔记·后端·数码相机·物联网·自动化·音视频
Hello-FPGA3 天前
PCIe-4005 相机模拟器在视觉系统开发中的实战应用
数码相机