4、经典去马赛克算法:双线性插值、边缘导向插值、色差恒定假设
好,咱们今天聊点实在的。去马赛克算法,说白了就是怎么把 Bayer 格式的 RAW 图,变成一张正常的彩色照片。你想想看,每个像素点只记录了红、绿、蓝中的一种颜色,另外两种颜色全靠猜。怎么猜得准?这就是算法的本事了。
我最早接触这块的时候,用的是最简单的双线性插值。效果嘛……嗯,只能说能出图。后来做项目被甲方吐槽“边缘全是锯齿”,才老老实实去研究边缘导向和色差恒定。今天我把这三个经典方法串起来讲,都是我自己踩过坑之后的理解。
4.1 双线性插值:最朴素的猜法
双线性插值的思路很直接——缺失的颜色,用周围最近的同色像素取平均。举个例子,一个红色像素点缺蓝色和绿色,那就把它上下左右四个绿色像素的平均值当作它的绿色,蓝色同理。
具体到 Bayer 格式,常见的 RGGB 排列下,绿色像素占一半,红蓝各占四分之一。插值的时候分两种情况:
- 中心像素是绿色:红色和蓝色分别取对角线方向的两个同色像素平均。
- 中心像素是红色或蓝色:绿色取上下左右四个绿色像素平均,另一种颜色取四个对角同色像素平均。
代码实现其实很简单,我贴一段核心逻辑:
// 伪代码:双线性插值绿色通道
for each pixel (i, j) in Bayer image:
if pixel is Red or Blue:
G(i,j) = ( G(i-1,j) + G(i+1,j) + G(i,j-1) + G(i,j+1) ) / 4
else:
G(i,j) = raw value
4.2 边缘导向插值:让算法学会“看方向”
双线性插值的问题在于,它不管图像内容,一律平均。但你想,如果当前像素在一条垂直边缘上,那垂直方向的颜色变化应该很小,水平方向变化很大。这时候用垂直方向的像素来插值,显然更合理。
边缘导向插值的核心就是:先判断边缘方向,再选择插值方向。
判断方向的方法有很多,最经典的是计算水平和垂直方向的梯度:
// 计算绿色通道的水平和垂直梯度
delta_H = |G(i,j-1) - G(i,j+1)|
delta_V = |G(i-1,j) - G(i+1,j)|
if delta_H < delta_V:
// 水平方向更平滑,用水平像素插值
G(i,j) = (G(i,j-1) + G(i,j+1)) / 2
else if delta_V < delta_H:
// 垂直方向更平滑,用垂直像素插值
G(i,j) = (G(i-1,j) + G(i+1,j)) / 2
else:
// 两个方向差不多,用四个像素平均
G(i,j) = (G(i-1,j) + G(i+1,j) + G(i,j-1) + G(i,j+1)) / 4
你看,逻辑并不复杂。但效果提升很明显——边缘处的锯齿和伪色大幅减少。
我在项目中遇到过一个问题:当图像纹理非常密集时,梯度判断会出错。比如细条纹衬衫,水平垂直梯度都很接近,算法就退化成双线性了。后来我加了多尺度梯度判断,才勉强搞定。嗯,这个后面讲自适应算法时会细说。
4.3 色差恒定假设:从物理模型出发
前面两种方法都是纯数学插值,没考虑颜色本身的物理特性。色差恒定假设就不一样了——它基于一个观察:在图像的局部区域,不同颜色通道之间的差值(或比值)变化很缓慢。
用人话说就是:R-G 的值在物体内部基本不变,只在边缘处跳变。这个假设在大部分自然图像上都成立,因为光照变化对三个通道的影响是同步的。
基于这个假设,去马赛克流程变成了两步:
- 先插值绿色通道(用边缘导向或双线性都行)。
- 再基于色差恒定恢复红蓝通道:比如要恢复红色像素位置的蓝色值,先计算周围已知蓝色像素的 B-G 差值,然后插值这个差值,最后加上绿色值得到蓝色。
公式看起来更清晰:
// 色差恒定法恢复蓝色通道
// 已知:在蓝色像素位置,B_raw 已知,G 已插值
// 目标:在红色像素位置恢复 B
// 1. 计算已知蓝色像素位置的色差
diff_BG = B_raw - G_interpolated
// 2. 对 diff_BG 做双线性插值,得到红色像素位置的色差
diff_BG_red = bilinear_interpolate(diff_BG, red_positions)
// 3. 恢复蓝色值
B_red = G_red + diff_BG_red
4.4 三种算法对比
我把这三个方法的核心差异整理成了一张表,方便你对照:
| 算法 | 核心思想 | 绿色通道 | 红蓝通道 | 计算量 | 典型伪影 |
|---|---|---|---|---|---|
| 双线性插值 | 邻域平均 | 四邻域平均 | 对角平均 | 极低 | 锯齿、伪色 |
| 边缘导向插值 | 梯度导向 | 边缘方向加权 | 双线性或引导 | 低 | 纹理密集区退化 |
| 色差恒定假设 | 颜色差值缓变 | 任意方法 | 色差插值+重建 | 中 | 边缘过冲/光晕 |
我个人习惯是:快速原型用双线性,追求画质用色差恒定+边缘导向的组合。但注意,色差恒定假设不是万能的,后面章节我会讲怎么用自适应权重来弥补它的短板。
4.5 知识结构图
下面这张图把三种算法的关系和演进路径画出来了,你看一眼就能记住整体脉络:
从图上你能看出来,这三种算法不是互斥的,而是层层递进的关系。双线性是基础,边缘导向解决了方向问题,色差恒定引入了颜色模型。实际工程中,我通常会把边缘导向和色差恒定结合起来——用边缘导向插绿色,用色差恒定恢复红蓝,效果比单独用任何一个都好。