相机对着一座彩色小房子按下快门,镜头把光投到图像传感器上。传感器收到的是光,它怎么知道屋顶是红色,草地是绿色?
我们从一只光电二极管开始。它先记录一个位置的明暗。许多光电二极管组成阵列后,可以得到黑白图像。再给它们加上彩色滤光片,传感器才有机会分辨红、绿、蓝。
光电二极管
光电二极管(photodiode)可以感知光线的变化。光子进入光电二极管后会产生电子。这些电子积累成电荷,相机可以读出电荷量。
保持曝光时间不变,光线越强,光电二极管积累的电荷越多。读出电路会把电荷量转换成电压。在下面的实验里,电荷越多,电压表的读数越大。可以调节手电筒的亮度,看看电压会怎样变化。
光电二极管的光电转换实验
电压表显示读出电路的输出电压,量程为 0 到 3.3 V。
一个光电二极管只能记录一个位置的明暗。如果把许多光电二极管横竖排列起来,会得到什么?
简易图像传感器
把许多光电二极管横竖排列起来,就可以得到一个简单的图像传感器。每只光电二极管记录一个位置的明暗,放在一起就是一幅黑白图像。
看一下彩色小房子经过镜头后,图像传感器会收到怎样的画面。镜头形成的像是倒立的,相机读取后可以再把它翻转回来。
小房子的镜头成像实验
图像传感器记录了房子的明暗,屋顶和草地的颜色已经消失。
现在能看见房子的轮廓了,红色屋顶和绿色草地却只剩下深浅不同的灰色。怎样才能知道光里有多少红色、绿色和蓝色?
彩色滤光片
彩色滤光片是一片带颜色的透明材料。它主要让一部分颜色的光通过,其余光会被吸收或反射。白光穿过红色滤光片后,留下的光就会偏红。
一块图像传感器由许多光电二极管组成。把红色滤光片放在整块传感器前面,每个位置仍然记录光强,但只记录红光带来的亮度。换成绿色或蓝色滤光片,就会得到 G 或 B 通道。
把红、绿、蓝三片滤光片依次放到同一块图像传感器前,看看传感器正在记录哪个颜色通道。
一片滤光片让传感器记录一个颜色通道
换一次滤光片,只能拍到一个颜色通道。连续换三次滤光片,无法记录同一个瞬间。要同时得到 R、G、B 通道,可以把光分成三路同时记录。
三传感器相机
小房子的光先经过镜头,再由分光棱镜分成三路。每路光穿过对应的 R、G、B 滤光片,最后落到三块相同的图像传感器上。
点一下 R、G、B 三条光路,可以顺着滤光片、图像传感器和通道图像看完整过程。
三传感器相机的成像过程
三块传感器加上分色棱镜,机身会更大,价格也会更高。
这种相机需要三块传感器,还要加入分色棱镜并对准三幅图像。机身更大,价格也更高。广播电视和专业摄像机用过这种结构,大多数消费相机选择了另一条路:把三种滤光片放在同一块传感器上。
CFA 彩色滤光阵列
把红、绿、蓝三种滤光片交错铺在一块传感器上,就得到了 CFA(Color Filter Array,彩色滤光阵列)。每个位置主要接受 R、G、B 中一种颜色的光,相邻位置记录另外两种颜色。
从左往右看一次:小房子的光经过镜头,在传感器上形成 Bayer RAW。相机把 RAW 拆成三个稀疏通道,补齐空格后,再把 R、G、B 合成彩色图像。点击步骤名称,可以看清每一步发生了什么。
三种滤光片铺在同一块传感器上
CFA 让每个位置只留下一个颜色的实测值。
CFA 只用一块传感器就能记录颜色,但每个位置仍缺少两个颜色。
拜耳阵列:一个位置只测一种颜色
Bayer 阵列是最常见的一种 CFA,以 2×2 单元重复。RGGB 的基本单元是:
R GG B四种常见 Bayer 排列使用相同的颜色比例,只改变坐标原点处的相位。
| Bayer 排列 | 2×2 单元 | 左上角通道 |
|---|---|---|
| RGGB | R G / G B | R |
| BGGR | B G / G R | B |
| GRBG | G R / B G | G |
| GBRG | G B / R G | G |
切换 CFA 排列方式
左上角从 R 开始,绿色占一半。
数码相机中常见的 Bayer 排列。
2×2 Bayer 单元:R × 1,G × 2,B × 1。
绿色占一半采样位置。人眼的亮度敏感度以及自然图像中的大量空间细节都与绿色附近的响应关系密切,提高绿色采样密度能在颜色信息与空间细节之间取得实用平衡。。这是 Bayer 在颜色采样密度与图像细节之间采用的一种取舍,不能把传感器的 G 响应直接等同于人眼亮度响应。
RGGB、BGGR、GRBG 和 GBRG 使用相同的颜色比例,只改变排列的起点。RYYB 和 X‑Trans 换了滤光片或重复单元,Debayer 寻找邻居的方法也要跟着换。
裁掉一行、旋转图像或读错元数据,也会改变坐标原点与 CFA 排列的对应关系。
传感器得到的 Bayer RAW
曝光结束后,相机把每个位置记录的数值读出来,并按传感器上的位置排成矩阵。这些还没有补齐颜色的数据,就是 Bayer RAW。
一张 2400 万像素的 Bayer RAW 包含 2400 万个实测值,不是 2400 万组完整的 RGB。每个位置只有一个数字,这个数字属于 R、G、B 中的一种颜色。
为了方便观察,我们常把 RAW 按照滤光片的颜色画成马赛克。画面中的红、绿、蓝只用来标出 CFA 位置,它还不是相机最后输出的彩色图像。
Debayer 算法
不要被这个名字吓到。Debayer 算法做的事,就是把 Bayer 传感器得到的 RAW 数据还原成彩色图像。这个过程也叫 Demosaic(去马赛克)。
Debayer 实际上在“猜”。一个位置只测到 R、G、B 中的一种颜色,算法会参考周围已经测到的像素,猜出缺少的另外两种颜色。这里的猜不是随机选择,而是根据邻近颜色和画面变化进行估算。
假设一个位置只测到了 R,那么它的状态是 R = 实测值,G = ?,B = ?。Debayer 保留 R,再猜出 G 和 B。它会在整张 RAW 上重复这个过程:
- 根据坐标和 Bayer 排列判断这个数值属于哪个通道。
- 保留传感器实际测到的数值。
- 参考邻近像素,猜出另外两个通道。
常见的补色方法有三种:
| 方法 | 怎么猜 | 容易出现的问题 |
|---|---|---|
| 最近邻 | 直接复制距离最近的同色像素 | 色块、锯齿、通道错位 |
| 双线性 | 对附近符合 CFA 位置关系的同色像素取平均 | 边缘变软、假色、拉链纹 |
| 方向感知 | 先判断边缘方向,再沿变化较小的方向计算 | 噪声、斜线和重复纹理可能误导方向判断 |
三种方法补的都是缺少的颜色,区别在于参考哪些邻居,以及怎样使用这些邻居。
逐像素看三种补色方法
下面每一格都有一个字母和一个数字。字母表示这里用了哪种滤光片,数字是传感器实际测到的 RAW 值。选择任意一格,再按步骤查看它缺少哪两种颜色,以及算法参考了哪些邻居。
点一个 RAW 位置,看三种算法怎样猜颜色
这个位置实测的是 R
这一格的字母是 R,RAW 数值是 107。另外两个通道还没有数值。
图像边缘没有完整邻域。实验允许选择最外圈像素,并使用镜像填充:越过边界的坐标映射回图内。生产实现也可能复制边缘、缩小有效输出区域,或为边界设计专用滤波核。算法和测试代码必须采用同一种策略。
三种补色算法的实现
最近邻:复制距离最近的同色样本
设 表示 CFA 中实测通道 的坐标集合。最近邻先找到与目标位置 距离最小的同色坐标 ,再复制该位置的数值:
多个候选位置可能具有相同距离,代码需要规定固定的遍历或优先顺序。最近邻计算量小,适合作为速度基线;一份实测值被复制到多个输出位置后,轮廓附近容易出现色块和阶梯。
下面继续使用互动组件默认选中的 R 像素。整块传感器采用 RGGB 排列,截取到这个 R 像素附近时,3×3 CFA 是 BGB / GRG / BGB。代码按从上到下、从左到右的顺序寻找最近样本;距离相同时,选择先找到的一个。
# Bayer 排列:RGGB;目标是中心的 R 像素raw = [ [235, 158, 102], # B G B [158, 107, 189], # G R G [235, 158, 122], # B G B]cfa = ["BGB", "GRG", "BGB"]target = (1, 1)
def nearest(channel): row, column = target points = [ (r, c) for r in range(3) for c in range(3) if cfa[r][c] == channel ] r, c = min( points,7 collapsed lines
key=lambda point: (point[0] - row) ** 2 + (point[1] - column) ** 2, ) return raw[r][c]
rgb = (raw[1][1], nearest("G"), nearest("B"))print(rgb) # (107, 158, 235)双线性:按位置选择邻居
双线性 Debayer 根据目标位置和目标通道选择邻域,不会把周围八个数字混在一起平均。
在 RGGB 的 R 位置,G 来自上、下、左、右四个绿色样本:
B 来自四个对角蓝色样本:
G 位置缺失的 R 与 B 分别来自水平或垂直方向,方向取决于当前 G 所在的 CFA 相位。双线性假设局部颜色平滑变化;高对比边缘破坏这个假设,跨边缘平均会混合两个物体。
在同一个 RGGB 样本中,中心 R 是实测值。缺少的 G 使用上、下、左、右四格,缺少的 B 使用四个对角位置。
# Bayer 排列:RGGB;目标是中心的 R 像素raw = [ [235, 158, 102], # B G B [158, 107, 189], # G R G [235, 158, 122], # B G B]
r = raw[1][1] # 实测值g = sum([raw[0][1], raw[2][1], raw[1][0], raw[1][2]]) / 4b = sum([raw[0][0], raw[0][2], raw[2][0], raw[2][2]]) / 4
rgb = tuple(int(value + 0.5) for value in (r, g, b))print(rgb) # (107, 166, 174)教学版方向感知:比较不同方向的变化
本文使用一个能补齐三个通道的教学版本。算法沿水平、垂直和两条对角线寻找成对的同色样本,再比较每一对样本的变化。目标通道在某些方向上找不到同色样本时,算法只比较能够找到的一组。
例如,在 R 或 B 位置猜 G 时,左右和上下都有绿色样本。算法先计算两组变化:
时,水平方向变化较小,算法用左右两个 G 的平均值; 时改用上下两个 G。两者相等时,算法退回四邻域平均:
在 R 位置猜 B,或者在 B 位置猜 R 时,同色样本位于两条对角线上。算法改为比较左上到右下、右上到左下两组变化。G 位置缺少的 R 或 B 通常只能在水平或垂直方向找到一对直接相邻的同色样本。
这个教学算法让 R、G、B 都使用方向信息,但它仍比相机中的实现简单。完整算法还可能先补 G,再插值 R-G、B-G 色差,并使用更大的邻域。噪声、斜线和重复纹理仍可能让它选错方向。
# Bayer 排列:RGGB;目标是中心的 R 像素raw = [ [235, 158, 102], # B G B [158, 107, 189], # G R G [235, 158, 122], # B G B]
def choose_pair(first, second): change = abs(first - second) value = (first + second) / 2 return change, value
# G 比较水平和垂直方向g_horizontal = choose_pair(raw[1][0], raw[1][2])g_vertical = choose_pair(raw[0][1], raw[2][1])g = min(g_horizontal, g_vertical)[1]
# B 比较两条对角线7 collapsed lines
b_main_diagonal = choose_pair(raw[0][0], raw[2][2])b_other_diagonal = choose_pair(raw[0][2], raw[2][0])b = min(b_main_diagonal, b_other_diagonal)[1]
r = raw[1][1] # 实测值rgb = tuple(int(value + 0.5) for value in (r, g, b))print(rgb) # (107, 158, 179)CFA 采样与颜色重建的局限
CFA 让一块传感器记录下颜色,也留下了两个限制:每个位置只测到一种颜色,排列太密的细节还可能超过传感器的采样能力。
同一份 RAW,三种算法会补成什么样
还是前面那座小房子。传感器得到的 Bayer RAW 没有变,现在只换补色算法。看一下屋顶斜边和窗框,三种算法会把它们补成什么样。
给同一份 RAW 换一种补色算法
最近邻直接搬来旁边的颜色,屋顶边缘容易变成一格一格的色块。双线性把几个邻居放在一起平均,色块少了,边缘也会变软。方向感知先比较不同方向的变化,再沿变化较小的方向补色,斜边通常会更完整。
“平均差”只比较这张合成小房子的数值。看一张真实照片时,还要检查边缘有没有彩边和小齿。
假色与拉链纹
屋顶外面冒出的红色、青色或紫色,是假色。一条平滑的斜边变成明暗交替的小齿,是拉链纹。
| 现象 | 你会看到什么 | 算法哪里猜错了 |
|---|---|---|
| 假色(False color) | 中性边缘旁出现错误颜色 | 算法把物体的明暗变化当成了颜色变化 |
| 拉链纹(Zippering) | 斜边出现交替的小齿 | 算法在边缘两侧来回更换邻居或方向 |
拍摄纱窗、织物或显示器时,画面里还可能出现更大的波纹。灰度传感器也会遇到这个问题,它叫摩尔纹。
细纹超过采样能力:摩尔纹
细纹排列得太密,像素来不及把它们逐条记下来。传感器会把这些细纹记成另一种更粗的波纹,这种现象叫摩尔纹。
调高下面的细纹密度,先看灰度传感器什么时候出现波纹,再比较同一幅细纹经过 Bayer 采样和 Debayer 后会增加什么颜色。
把细纹变密,看看传感器记下了什么
灰度传感器和 Bayer 传感器同时拍摄一幅细纹。
灰度传感器仍能分开这些细纹。Bayer 的单个颜色通道采样更稀,补色后已经出现假色。
灰度传感器也会产生摩尔纹。Bayer 传感器的 R、G、B 分布在不同位置,摩尔纹旁边还可能出现假色。摩尔纹来自采样不足,假色来自三个颜色通道没有在同一位置采样。
细纹超过采样上限以后,传感器没有记录足够的信息。更复杂的 Debayer 可以减轻错误,却无法找回唯一的原始纹理。相机通常从两个方向处理这个问题:
- 在光到达传感器前,用光学低通滤镜压低过密的细纹;
- 增加像素数量,让传感器能够记录更密的结构。
更复杂的 Debayer 算法
前面的方向感知只比较几对相邻像素。遇到细纹、噪声或复杂边缘时,它仍然可能选错方向。为了减少这些错误,人们又研究了许多 Debayer 算法。
- AHD:先沿水平和垂直方向各补一次,再选择颜色变化更平滑的结果。
- LMMSE:比较不同方向的颜色差,并把噪声可能带来的误差算进去。
- AMaZE:检查更多方向和梯度,重点减少混叠与拉链纹。
- 神经网络 Debayer:从大量图像中学习怎样补色,还可以把补色和降噪放在一起处理。
这些算法并不是越新就一定越好。细节、噪声、计算速度和功耗不同,适合的算法也会不同。感兴趣的话,可以用上面的名称继续查找资料。不过,再复杂的 Debayer 也只能减少猜错,无法找回传感器从未记录的信息。
真实相机还要处理什么
前面的实验假设 RAW 数据已经很干净。真实传感器还会带着黑电平、坏点、镜头阴影和噪声。相机先校正 RAW,再补齐颜色,最后完成颜色和输出处理。
点一下 RAW 校正、Debayer 和输出处理,可以看见数据在三个阶段中的变化。
从 RAW 到彩色照片
不同相机会拆分、交换或合并其中一些步骤。
- Debayer 之前,相机会修正黑电平、坏点和镜头阴影。坏点如果没有先处理,错误的数值还会被补到周围像素。
- Debayer 时,相机必须知道 CFA 的排列方式和起始位置。RAW 被裁切、旋转或翻转以后,这个位置也要跟着变化。
- Debayer 之后,图像还要经过白平衡、颜色转换、降噪、锐化和编码,最后才能得到常见的 JPEG 或 HEIF。
不同相机会调整这些步骤的先后顺序。Debayer 通常在线性的 RAW 数据上计算,并保留足够的中间精度。如果过早加入 Gamma 或 Tone Curve,邻居像素的平均值就会失去原来的意义。
照片里的彩边也不一定来自 Debayer。镜头色差、物体运动、传感器串扰和过强锐化,都可能产生相似的颜色边缘。
总结
相机没有在每个位置测量完整的 RGB。它先用 CFA 记录一份不完整的 RAW,再由 Debayer 根据周围像素补齐颜色。算法可以猜得越来越好,但不能把没有记录的信息重新变出来。
参考资料
下拉加载评论