3、传统ISP核心模块:去马赛克(Demosaic)、白平衡(AWB)、色彩校正矩阵(CCM)
各位同学,欢迎来到第三章。前两章我们聊了ISP的整体流水线和传感器的基础知识。今天,咱们要深入三个最核心、也最“传统”的模块:去马赛克、白平衡和色彩校正矩阵。
这三个模块,说白了,就是决定一张照片“清不清晰”、“颜色对不对”的关键。我当年刚入行时,觉得这些算法都是现成的,调调参数就行。直到有一次,一个项目在室内灯光下颜色总是偏黄,怎么调都调不好……嗯,从那以后,我才真正沉下心来研究这些基础模块。今天,我就把我在项目中踩过的坑和积累的经验,一并分享给你们。
3.1 去马赛克(Demosaic)——从“黑白灰”到“彩色世界”
传感器上的每个像素,其实只能感知光的强度,不区分颜色。为了得到彩色图像,我们在传感器表面覆盖了一层彩色滤光片阵列(CFA),最常见的就是Bayer格式。每个像素只采集红、绿、蓝中的一种颜色。
那问题来了:每个像素只有一种颜色信息,我们怎么得到全彩图?
这就是去马赛克要做的事。它通过周围像素的信息,把缺失的另外两种颜色“猜”出来。你想想看,这本质上就是一个插值问题。
3.1.1 双线性插值——最朴素的方法
最简单的做法,就是对每个像素,直接用周围相邻的同色通道像素取平均。比如一个绿色像素,它缺失的红色值,就用上下左右四个红色像素的平均值来填充。
这个方法计算量小,但缺点也很明显。我在项目中用过一次,结果在图像边缘和纹理丰富的地方,全是彩色伪影,看着特别“脏”。
核心问题:双线性插值没有考虑图像边缘的方向,导致边缘处出现“拉链效应”和“假彩色”。
3.1.2 边缘导向插值——更聪明的做法
为了解决上面的问题,业界提出了边缘导向插值。它的思路是:先判断当前像素是在水平边缘上,还是在垂直边缘上,然后只沿着边缘方向进行插值。
举个例子,如果一个像素的左右两边颜色差异小,上下差异大,那它很可能在水平边缘上。这时候,我们就只用左右像素来插值,避免“跨过”边缘。
// 伪代码:边缘导向插值(绿色通道)
if (abs(G_left - G_right) < abs(G_up - G_down)) {
// 水平边缘,用左右插值
G_missing = (G_left + G_right) / 2;
} else {
// 垂直边缘,用上下插值
G_missing = (G_up + G_down) / 2;
}
我的经验:边缘导向插值在大多数场景下效果不错,但在45度斜线边缘上还是会出问题。后来我改用自适应插值,结合多个方向梯度,效果才稳定下来。
3.2 白平衡(AWB)——让“白色”回归白色
你有没有发现,在室内白炽灯下拍的照片,整体会偏黄;在阴天户外,又会偏蓝。这是因为不同光源的色温不同,导致传感器记录的RGB值发生了偏移。
白平衡的目的,就是消除这种光源色温带来的色偏,让白色物体在任何光源下都呈现为白色。
3.2.1 灰度世界法——简单但有效
这个算法基于一个假设:一张色彩丰富的自然图像,其R、G、B三个通道的平均值应该趋于相等(即“灰度”)。
具体做法是:分别计算整张图的R、G、B均值,然后计算每个通道的增益,让三个均值相等。
// 灰度世界法伪代码
float avgR = mean(R_channel);
float avgG = mean(G_channel);
float avgB = mean(B_channel);
float gainR = avgG / avgR;
float gainB = avgG / avgB;
// 应用增益
R_out = R_in * gainR;
B_out = B_in * gainB;
注意:灰度世界法在场景中某种颜色占主导时(比如大片草地),会失效。我曾经在一个全是绿色植物的场景中测试,结果图像被强行拉成了灰色,看起来非常诡异。
3.2.2 完美反射法——另一种思路
这个算法假设图像中最亮的像素点,应该是纯白色的(即R=G=B)。它通过找到这些“参考白点”,来计算增益。
我个人习惯把两种方法结合起来用。先分别计算,然后根据场景的色温估计值,做一个加权融合。这样鲁棒性会好很多。
3.3 色彩校正矩阵(CCM)——给颜色“校准”
经过白平衡校正后,图像的颜色大致对了,但还不够“准”。为什么?因为传感器的光谱响应曲线和人眼并不完全一致。简单说,传感器看到的红色,和人眼看到的红色,是有偏差的。
CCM的作用,就是通过一个3x3的矩阵,把传感器记录的RGB值,映射到标准色彩空间(比如sRGB)下。
3.3.1 3x3矩阵变换
这个变换很简单,就是线性代数里的矩阵乘法:
[R_out] [a11, a12, a13] [R_in]
[G_out] = [a21, a22, a23] * [G_in]
[B_out] [a31, a32, a33] [B_in]
矩阵中的9个系数,通常是通过拍摄标准色卡(比如X-Rite ColorChecker)来标定得到的。你想想看,这个过程本质上是一个线性回归问题。
3.3.2 色域映射与饱和度控制
CCM不仅能校正色偏,还能控制图像的饱和度和色调。比如,你可以通过调整矩阵系数,让红色更“鲜艳”一些,或者让肤色更“自然”一些。
关键点:CCM矩阵的标定,需要针对不同的光源(D65、A光源等)分别进行。我在项目中就吃过这个亏,只标定了D65光源,结果在室内白炽灯下,颜色完全不对。
| 光源类型 | 色温 (K) | 典型场景 | CCM标定要求 |
|---|---|---|---|
| D65 | 6500 | 晴天户外 | 标准 |
| A光源 | 2856 | 白炽灯 | 需单独标定 |
| TL84 | 4000 | 商场荧光灯 | 需单独标定 |
避坑指南:我曾经为了省事,只用一个CCM矩阵打天下。结果在混合光源场景下,图像的颜色完全失控。后来我老老实实做了多光源标定,并在运行时根据色温估计值做矩阵插值,问题才解决。