OpenISP 模块拆解 · 第16讲:亮度对比度控制 (BCC)
模块定位
BCC,即 Brightness Contrast Control,代码位于 model/bcc.py。它是 ISP 后段的基础图像调节模块,通常作用在 YUV 的 Y 通道上,用来调整整体亮度和局部对比感。
相比 Gamma 或 tone mapping,BCC 更简单直接:亮度是平移,对比度是围绕某个中心点拉伸或压缩。
背景原理
亮度调整可以写成:
text
Y_bright = Y + brightness
对比度调整常写成:
text
Y_contrast = center + (Y - center) * factor
其中 center 常取 127 或 128。大于中心的值被拉得更高,小于中心的值被压得更低,对比度增强;反过来则对比度降低。
openISP 实现
BCC 输入参数:
img: 单通道图像,通常是 Y。brightness: 亮度偏移。contrast: 对比度系数。clip: 输出上限。
代码执行:
text
bcc_img = img + brightness
bcc_img = bcc_img + (img - 127) * contrast
注意第二行使用的是原始 self.img 与 127 的差,而不是第一步亮度调整后的 bcc_img。因此实际公式为:
text
out = img + brightness + (img - 127) * contrast
如果 contrast = 0,只调亮度;如果 contrast > 0,亮部更亮、暗部更暗;如果 contrast < 0,对比度下降。
为什么通常作用在 Y 通道
如果直接对 RGB 三通道分别做亮度/对比度,可能改变通道比例,导致色相和饱和度偏移。对 Y 通道处理能更接近"只改变明暗,不改变颜色"的目标。
这也是前面 CSC 转 YUV 的意义之一:把明暗调节和色彩调节拆开。
参数和调试
brightness > 0: 整体变亮,暗部抬起,高光更容易 clip。brightness < 0: 整体变暗,阴影更容易压死。contrast > 0: 对比增强,但可能丢黑白两端细节。contrast < 0: 对比降低,画面更灰。clip: 限制输出范围,通常 8-bit 为 255。
调试时看灰阶、肤色、暗部和高光。BCC 很容易让图像"看起来更有劲",但过量会损失动态范围。
与 Gamma 的区别
BCC 是简单线性操作:平移加拉伸。Gamma 是非线性曲线,会对暗部、中间调和亮部分配不同变化量。BCC 更像基础旋钮,Gamma 更像 tone curve。
实际 pipeline 中,二者可以同时存在:Gamma 负责整体视觉曲线,BCC 负责后段微调或用户设置。
实现注意点
当前输出数组先创建为 np.int16,然后进行加法和乘法,最后 clip。这样可以承接负亮度和对比度产生的中间负值。
如果 contrast 不是很小的比例,而是固定点参数,当前公式没有除以 scale;因此使用时必须确认配置约定。文档按源码行为解释,不额外假设隐藏缩放。
学习重点
- 亮度是整体 offset,对比度是围绕中心点拉伸。
- BCC 适合在 Y 通道做,减少色偏。
- BCC 是线性操作,Gamma 是非线性操作。
- 调得过强会造成 clip、阴影压死或画面发灰。
面试问答
Q1: 亮度和对比度有什么区别?
亮度是整体平移所有像素值;对比度是让像素远离或靠近中心灰点,改变明暗差距。
Q2: 为什么对比度公式要减 127?
127 近似 8-bit 中间灰。围绕中点拉伸可以让亮部和暗部向相反方向变化。
Q3: BCC 为什么放在 Y 通道?
这样主要改变明暗,不直接破坏 RGB 通道比例,色相更稳定。
Q4: BCC 过强会导致什么?
高光 clip、暗部压死、灰阶断层,或者画面过灰、缺少层次。
Q5: BCC 和 Gamma 有什么区别?
BCC 是线性亮度/对比度调节;Gamma 是非线性曲线,更多影响不同亮度区间的码值分配。