多核架构中,RTOS小核跑sensor 的normal模式,大核linux核跑WDR模式,把小核的曝光时间映射到WDR模式中的曝光时间的方法
上述博文讲解了sensor normal模式转到WDR模式自动曝光baog的de映射方法。其中自动曝光比的系数为关键调参。实际工程应用中应该根据场景中实际的动态方法设定合适的自动曝光比系数。背光或者宽动态范围较大的场景Tshort/Tlong需要设置小一点,普通场景Tshort/Tlong适当设置大一点。
如何根据单帧图像计算其动态范围指标系数呢?
1. 动态范围的本质
动态范围 = 图像中最亮有效信号 与最暗有效信号的比值。
换句话说:
DR ≈ log2 (最大可用亮度 / 最小可用亮度)
但 "可用" 不是简单的 max 和 min,因为:
- 最亮点可能是噪点
- 最暗点可能是死像素
- 中间可能有过曝或欠曝区域
所以必须用统计方法来估计。
2. 单张图像 DR 检测的核心思路
单张图没有多张曝光,所以我们只能从 ** 亮度分布(直方图)** 中推断 DR。
核心思想:
- 找 "真正有内容的最亮点"(不是噪点)
- 找 "真正有内容的最暗点"(不是死黑)
- 计算两者的比值
- 用 log2 得到 DR(单位 EV)
3. 工程上最常用的方法:基于直方图的 DR 估计
下面是最经典、最稳定的方法。
方法 A:直方图两端截尾法(Truncated Histogram)
步骤:
- 计算图像的亮度直方图(Y 通道)。
- 从直方图的两端去掉一定比例的异常值(例如 0.5%)。
- 剩下的直方图的左右边界就是 "有效亮度范围"。
- 计算 DR。
公式:
DR ≈ log2( (max_valid_lum) / (min_valid_lum) )
为什么有效?
- 去掉两端可以排除噪点、死像素、孤立亮点。
- 剩下的部分基本就是 "真实场景内容"。
优点:
- 计算快
- 稳定
- 不需要多张曝光
缺点:
- 受对比度、噪声影响较大
方法 B:基于熵的 DR 估计(Entropy-based DR)
思想:
图像的信息熵越大,说明亮度分布越均匀,动态范围可能越大。
步骤:
- 计算亮度直方图。
- 计算直方图的熵:
Entropy = -Σ(p * log2(p))
- 用经验公式把熵映射到 DR:
DR ≈ a * Entropy + b
a、b 通过大量图像训练得到。
优点:
- 对噪声不敏感
- 能反映 "信息量"
缺点:
- 依赖训练数据
- 不是真正物理意义上的 DR
方法 C:基于局部对比度的 DR 估计
思想:
动态范围大的图像,局部区域的亮暗变化更剧烈。
步骤:
- 将图像分成多个小块(如 16x16)。
- 对每个块计算局部对比度:
contrast = (max_lum - min_lum) / (max_lum + min_lum)
- 统计所有块的对比度分布。
- 对比度分布越广,说明 DR 越大。
优点:
- 能反映图像的 "局部细节丰富度"
- 对 HDR 图像敏感
缺点:
- 计算稍慢
- 对噪声敏感
方法 D:基于饱和 / 欠曝区域检测
思想:
动态范围小的图像更容易出现:
- 过曝(高光 clipping)
- 欠曝(暗部 clipping)
步骤:
- 检测图像中是否有大面积饱和区域(例如 Y > 245)。
- 检测是否有大面积欠曝区域(例如 Y < 10)。
- 如果两端都被 "切掉",说明 DR 被压缩了。
- 用未被切掉的部分估计 DR。
优点:
- 非常适合判断 "图像是否被压缩过"
- 对 HDR 图像特别有效
缺点:
- 对自然场景的 DR 估计不够直接
4. 最先进的方法:基于多尺度分解的 DR 估计
这是近几年论文里常用的方法。
思想:
动态范围大的图像,其细节在多尺度下都能保持清晰。
步骤:
- 对图像做多尺度分解(如拉普拉斯金字塔)。
- 计算每一层的能量。
- 能量分布越广,说明 DR 越大。
优点:
- 精度高
- 能反映真实场景的动态范围
缺点:
- 计算复杂
- 不适合实时系统
5. 工程上推荐的组合方案
如果你要在实际系统中使用,我建议:
直方图截尾法 + 饱和区域检测
原因:
- 速度快
- 稳定
- 抗噪性好
- 不需要训练
- 适合嵌入式平台
6.伪代码实现
cpp
float estimate_dynamic_range(uint8_t *y_channel, int width, int height) {
// 1. 计算直方图
int hist[256] = {0};
for (int i = 0; i < width * height; i++) {
hist[y_channel[i]]++;
}
// 2. 去掉两端 0.5% 的异常值
int total = width * height;
int cut = total * 0.005;
int left = 0, right = 255;
// 找左边界
int count = 0;
while (left < 255) {
count += hist[left];
if (count > cut) break;
left++;
}
// 找右边界
count = 0;
while (right > 0) {
count += hist[right];
if (count > cut) break;
right--;
}
// 3. 防止除以 0
if (left >= right) return 0.0f;
// 4. 计算 DR(假设亮度已归一化到 0~1)
float min_lum = left / 255.0f;
float max_lum = right / 255.0f;
// 加一个小偏移避免 log2(0)
min_lum = max(min_lum, 1e-6f);
// 5. 得到 DR(EV)
float dr = log2(max_lum / min_lum);
return dr;
}
7. 你可能会问:单张图的 DR 估计准确吗?
答案:
能达到 "工程可用",但不是物理真实 DR。
因为:
- 单张图可能被压缩过(JPEG、ISP 处理)
- 噪声会影响暗部估计
- 场景本身的对比度不等于物理动态范围
但它足够用来:
- 判断图像是否 HDR
- 判断是否需要 WDR 合成
- 判断是否欠曝 / 过曝
- 自动调整显示参数
- 作为 ISP 算法的输入